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
{
268 DWORD font_data_size
;
271 FONTSIGNATURE fs_links
;
273 FT_Fixed font_version
;
275 Bitmap_Size size
; /* set if face is a bitmap */
276 BOOL external
; /* TRUE if we should manually add this font to the registry */
277 struct tagFamily
*family
;
278 /* Cached data for Enum */
279 struct enum_data
*cached_enum_data
;
282 typedef struct tagFamily
{
284 const WCHAR
*FamilyName
;
285 const WCHAR
*EnglishName
;
291 INT adv
; /* These three hold to widths of the unrotated chars */
309 typedef struct tagHFONTLIST
{
324 struct list hfontlist
;
325 OUTLINETEXTMETRICW
*potm
;
326 DWORD total_kern_pairs
;
327 KERNINGPAIR
*kern_pairs
;
328 struct list child_fonts
;
330 /* the following members can be accessed without locking, they are never modified after creation */
332 struct font_mapping
*mapping
;
355 const WCHAR
*font_name
;
359 struct enum_charset_element
{
365 struct enum_charset_list
{
367 struct enum_charset_element element
[32];
370 #define GM_BLOCK_SIZE 128
371 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
373 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
374 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
375 #define UNUSED_CACHE_SIZE 10
376 static struct list child_font_list
= LIST_INIT(child_font_list
);
377 static struct list system_links
= LIST_INIT(system_links
);
379 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
381 static struct list font_list
= LIST_INIT(font_list
);
383 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
384 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
385 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
387 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
388 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
389 'W','i','n','d','o','w','s','\\',
390 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
391 'F','o','n','t','s','\0'};
393 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
394 'W','i','n','d','o','w','s',' ','N','T','\\',
395 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
396 'F','o','n','t','s','\0'};
398 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
399 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
400 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
401 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
403 static const WCHAR
* const SystemFontValues
[4] = {
410 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
411 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
413 /* Interesting and well-known (frequently-assumed!) font names */
414 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
415 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 };
416 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
417 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
418 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
419 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
420 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
421 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
423 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
424 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
425 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
426 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
427 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
428 'E','u','r','o','p','e','a','n','\0'};
429 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
430 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
431 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
432 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
433 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
434 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
435 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
436 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
437 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
438 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
439 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
440 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
442 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
452 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
460 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
469 typedef struct tagFontSubst
{
475 /* Registry font cache key and value names */
476 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
477 'F','o','n','t','s',0};
478 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
479 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
480 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
481 static const WCHAR face_italic_value
[] = {'I','t','a','l','i','c',0};
482 static const WCHAR face_bold_value
[] = {'B','o','l','d',0};
483 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
484 static const WCHAR face_external_value
[] = {'E','x','t','e','r','n','a','l',0};
485 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
486 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
487 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
488 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
489 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
490 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
491 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
492 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
505 static struct list mappings_list
= LIST_INIT( mappings_list
);
507 static CRITICAL_SECTION freetype_cs
;
508 static CRITICAL_SECTION_DEBUG critsect_debug
=
511 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
512 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
514 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
516 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
518 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
519 static BOOL use_default_fallback
= FALSE
;
521 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
523 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
524 'W','i','n','d','o','w','s',' ','N','T','\\',
525 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
526 'S','y','s','t','e','m','L','i','n','k',0};
528 /****************************************
529 * Notes on .fon files
531 * The fonts System, FixedSys and Terminal are special. There are typically multiple
532 * versions installed for different resolutions and codepages. Windows stores which one to use
533 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
535 * FIXEDFON.FON FixedSys
537 * OEMFONT.FON Terminal
538 * LogPixels Current dpi set by the display control panel applet
539 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
540 * also has a LogPixels value that appears to mirror this)
542 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
543 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
544 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
545 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
546 * so that makes sense.
548 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
549 * to be mapped into the registry on Windows 2000 at least).
552 * ega80woa.fon=ega80850.fon
553 * ega40woa.fon=ega40850.fon
554 * cga80woa.fon=cga80850.fon
555 * cga40woa.fon=cga40850.fon
558 /* These are all structures needed for the GSUB table */
560 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
561 #define TATEGAKI_LOWER_BOUND 0x02F1
577 GSUB_ScriptRecord ScriptRecord
[1];
583 } GSUB_LangSysRecord
;
588 GSUB_LangSysRecord LangSysRecord
[1];
592 WORD LookupOrder
; /* Reserved */
593 WORD ReqFeatureIndex
;
595 WORD FeatureIndex
[1];
601 } GSUB_FeatureRecord
;
605 GSUB_FeatureRecord FeatureRecord
[1];
609 WORD FeatureParams
; /* Reserved */
611 WORD LookupListIndex
[1];
630 } GSUB_CoverageFormat1
;
635 WORD StartCoverageIndex
;
641 GSUB_RangeRecord RangeRecord
[1];
642 } GSUB_CoverageFormat2
;
645 WORD SubstFormat
; /* = 1 */
648 } GSUB_SingleSubstFormat1
;
651 WORD SubstFormat
; /* = 2 */
655 }GSUB_SingleSubstFormat2
;
657 #ifdef HAVE_CARBON_CARBON_H
658 static char *find_cache_dir(void)
662 static char cached_path
[MAX_PATH
];
663 static const char *wine
= "/Wine", *fonts
= "/Fonts";
665 if(*cached_path
) return cached_path
;
667 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
670 WARN("can't create cached data folder\n");
673 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
676 WARN("can't create cached data path\n");
680 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
682 ERR("Could not create full path\n");
686 strcat(cached_path
, wine
);
688 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
690 WARN("Couldn't mkdir %s\n", cached_path
);
694 strcat(cached_path
, fonts
);
695 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
697 WARN("Couldn't mkdir %s\n", cached_path
);
704 /******************************************************************
707 * Extracts individual TrueType font files from a Mac suitcase font
708 * and saves them into the user's caches directory (see
710 * Returns a NULL terminated array of filenames.
712 * We do this because they are apps that try to read ttf files
713 * themselves and they don't like Mac suitcase files.
715 static char **expand_mac_font(const char *path
)
722 const char *filename
;
726 unsigned int size
, max_size
;
729 TRACE("path %s\n", path
);
731 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
734 WARN("failed to get ref\n");
738 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
741 TRACE("no data fork, so trying resource fork\n");
742 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
745 TRACE("unable to open resource fork\n");
752 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
755 CloseResFile(res_ref
);
759 out_dir
= find_cache_dir();
761 filename
= strrchr(path
, '/');
762 if(!filename
) filename
= path
;
765 /* output filename has the form out_dir/filename_%04x.ttf */
766 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
773 unsigned short *num_faces_ptr
, num_faces
, face
;
776 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
778 fond
= Get1IndResource(fond_res
, idx
);
780 TRACE("got fond resource %d\n", idx
);
783 fam_rec
= *(FamRec
**)fond
;
784 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
785 num_faces
= GET_BE_WORD(*num_faces_ptr
);
787 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
788 TRACE("num faces %04x\n", num_faces
);
789 for(face
= 0; face
< num_faces
; face
++, assoc
++)
792 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
793 unsigned short size
, font_id
;
796 size
= GET_BE_WORD(assoc
->fontSize
);
797 font_id
= GET_BE_WORD(assoc
->fontID
);
800 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
804 TRACE("trying to load sfnt id %04x\n", font_id
);
805 sfnt
= GetResource(sfnt_res
, font_id
);
808 TRACE("can't get sfnt resource %04x\n", font_id
);
812 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
817 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
819 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
820 if(fd
!= -1 || errno
== EEXIST
)
824 unsigned char *sfnt_data
;
827 sfnt_data
= *(unsigned char**)sfnt
;
828 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
832 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
835 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
837 ret
.array
[ret
.size
++] = output
;
841 WARN("unable to create %s\n", output
);
842 HeapFree(GetProcessHeap(), 0, output
);
845 ReleaseResource(sfnt
);
848 ReleaseResource(fond
);
851 CloseResFile(res_ref
);
856 #endif /* HAVE_CARBON_CARBON_H */
858 static inline BOOL
is_win9x(void)
860 return GetVersion() & 0x80000000;
863 This function builds an FT_Fixed from a double. It fails if the absolute
864 value of the float number is greater than 32768.
866 static inline FT_Fixed
FT_FixedFromFloat(double f
)
872 This function builds an FT_Fixed from a FIXED. It simply put f.value
873 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
875 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
877 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
881 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
886 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
887 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
889 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
890 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
892 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
894 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
896 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
900 file
= strrchr(face
->file
, '/');
905 if(!strcasecmp(file
, file_nameA
))
907 HeapFree(GetProcessHeap(), 0, file_nameA
);
912 HeapFree(GetProcessHeap(), 0, file_nameA
);
916 static Family
*find_family_from_name(const WCHAR
*name
)
920 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
922 if(!strcmpiW(family
->FamilyName
, name
))
929 static void DumpSubstList(void)
933 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
935 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
936 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
937 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
939 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
940 debugstr_w(psub
->to
.name
));
945 static LPWSTR
strdupW(LPCWSTR p
)
948 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
949 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
954 static LPSTR
strdupA(LPCSTR p
)
957 DWORD len
= (strlen(p
) + 1);
958 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
963 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
968 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
970 if(!strcmpiW(element
->from
.name
, from_name
) &&
971 (element
->from
.charset
== from_charset
||
972 element
->from
.charset
== -1))
979 #define ADD_FONT_SUBST_FORCE 1
981 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
983 FontSubst
*from_exist
, *to_exist
;
985 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
987 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
989 list_remove(&from_exist
->entry
);
990 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
991 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
992 HeapFree(GetProcessHeap(), 0, from_exist
);
998 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1002 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1003 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1006 list_add_tail(subst_list
, &subst
->entry
);
1011 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1012 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1013 HeapFree(GetProcessHeap(), 0, subst
);
1017 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1019 CHAR
*p
= strrchr(str
, ',');
1024 nc
->charset
= strtol(p
+1, NULL
, 10);
1027 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
1028 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1029 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
1032 static void LoadSubstList(void)
1036 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1040 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1041 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1042 &hkey
) == ERROR_SUCCESS
) {
1044 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1045 &valuelen
, &datalen
, NULL
, NULL
);
1047 valuelen
++; /* returned value doesn't include room for '\0' */
1048 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1049 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1053 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1054 &dlen
) == ERROR_SUCCESS
) {
1055 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1057 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1058 split_subst_info(&psub
->from
, value
);
1059 split_subst_info(&psub
->to
, data
);
1061 /* Win 2000 doesn't allow mapping between different charsets
1062 or mapping of DEFAULT_CHARSET */
1063 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1064 psub
->to
.charset
== DEFAULT_CHARSET
) {
1065 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1066 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1067 HeapFree(GetProcessHeap(), 0, psub
);
1069 add_font_subst(&font_subst_list
, psub
, 0);
1071 /* reset dlen and vlen */
1075 HeapFree(GetProcessHeap(), 0, data
);
1076 HeapFree(GetProcessHeap(), 0, value
);
1082 /*****************************************************************
1083 * get_name_table_entry
1085 * Supply the platform, encoding, language and name ids in req
1086 * and if the name exists the function will fill in the string
1087 * and string_len members. The string is owned by FreeType so
1088 * don't free it. Returns TRUE if the name is found else FALSE.
1090 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1093 FT_UInt num_names
, name_index
;
1095 if(FT_IS_SFNT(ft_face
))
1097 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1099 for(name_index
= 0; name_index
< num_names
; name_index
++)
1101 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1103 if((name
.platform_id
== req
->platform_id
) &&
1104 (name
.encoding_id
== req
->encoding_id
) &&
1105 (name
.language_id
== req
->language_id
) &&
1106 (name
.name_id
== req
->name_id
))
1108 req
->string
= name
.string
;
1109 req
->string_len
= name
.string_len
;
1116 req
->string_len
= 0;
1120 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1125 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1126 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1127 name
.language_id
= language_id
;
1128 name
.name_id
= name_id
;
1130 if(get_name_table_entry(ft_face
, &name
))
1134 /* String is not nul terminated and string_len is a byte length. */
1135 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1136 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1138 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1139 ret
[i
] = GET_BE_WORD(*tmp
);
1142 TRACE("Got localised name %s\n", debugstr_w(ret
));
1148 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1151 LONG r
= RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, &needed
);
1152 if(r
!= ERROR_SUCCESS
) return r
;
1153 if(type
!= REG_DWORD
|| needed
!= sizeof(DWORD
)) return ERROR_BAD_CONFIGURATION
;
1154 return RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &needed
);
1157 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1159 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1162 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
)
1165 DWORD num_strikes
, max_strike_key_len
;
1167 /* If we have a File Name key then this is a real font, not just the parent
1168 key of a bunch of non-scalable strikes */
1169 if(RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1173 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1174 face
->cached_enum_data
= NULL
;
1176 face
->file
= HeapAlloc(GetProcessHeap(), 0, needed
);
1177 RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, (BYTE
*)face
->file
, &needed
);
1179 face
->StyleName
= strdupW(face_name
);
1180 face
->family
= family
;
1182 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1184 WCHAR
*fullName
= HeapAlloc(GetProcessHeap(), 0, needed
);
1185 RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, (BYTE
*)fullName
, &needed
);
1186 face
->FullName
= fullName
;
1189 face
->FullName
= NULL
;
1191 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1192 reg_load_dword(hkey_face
, face_italic_value
, &italic
);
1193 reg_load_dword(hkey_face
, face_bold_value
, &bold
);
1194 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1195 reg_load_dword(hkey_face
, face_external_value
, (DWORD
*)&face
->external
);
1197 needed
= sizeof(face
->fs
);
1198 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1199 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1201 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1203 face
->scalable
= TRUE
;
1204 memset(&face
->size
, 0, sizeof(face
->size
));
1208 face
->scalable
= FALSE
;
1209 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1210 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1211 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1212 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1213 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1215 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1216 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1217 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1221 if (italic
) face
->ntmFlags
|= NTM_ITALIC
;
1222 if (bold
) face
->ntmFlags
|= NTM_BOLD
;
1223 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1225 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1226 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1227 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1228 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1230 if(!italic
&& !bold
)
1231 list_add_head(&family
->faces
, &face
->entry
);
1233 list_add_tail(&family
->faces
, &face
->entry
);
1235 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1238 /* do we have any bitmap strikes? */
1239 RegQueryInfoKeyW(hkey_face
, NULL
, NULL
, NULL
, &num_strikes
, &max_strike_key_len
, NULL
, NULL
,
1240 NULL
, NULL
, NULL
, NULL
);
1241 if(num_strikes
!= 0)
1243 WCHAR strike_name
[10];
1244 DWORD strike_index
= 0;
1246 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1247 while(RegEnumKeyExW(hkey_face
, strike_index
++, strike_name
, &needed
,
1248 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1251 RegOpenKeyExW(hkey_face
, strike_name
, 0, KEY_ALL_ACCESS
, &hkey_strike
);
1252 load_face(hkey_strike
, face_name
, family
);
1253 RegCloseKey(hkey_strike
);
1254 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1259 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1261 DWORD max_family_key_len
, size
;
1263 DWORD family_index
= 0;
1267 RegQueryInfoKeyW(hkey_font_cache
, NULL
, NULL
, NULL
, NULL
, &max_family_key_len
, NULL
, NULL
,
1268 NULL
, NULL
, NULL
, NULL
);
1269 family_name
= HeapAlloc(GetProcessHeap(), 0, (max_family_key_len
+ 1) * sizeof(WCHAR
));
1271 size
= max_family_key_len
+ 1;
1272 while(RegEnumKeyExW(hkey_font_cache
, family_index
++, family_name
, &size
,
1273 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1275 WCHAR
*english_family
= NULL
;
1276 DWORD face_index
= 0;
1278 DWORD max_face_key_len
;
1280 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1281 TRACE("opened family key %s\n", debugstr_w(family_name
));
1282 if(RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, NULL
, &size
) == ERROR_SUCCESS
)
1284 english_family
= HeapAlloc(GetProcessHeap(), 0, size
);
1285 RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)english_family
, &size
);
1288 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1289 family
->FamilyName
= strdupW(family_name
);
1290 family
->EnglishName
= english_family
;
1291 list_init(&family
->faces
);
1292 list_add_tail(&font_list
, &family
->entry
);
1296 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1297 subst
->from
.name
= strdupW(english_family
);
1298 subst
->from
.charset
= -1;
1299 subst
->to
.name
= strdupW(family_name
);
1300 subst
->to
.charset
= -1;
1301 add_font_subst(&font_subst_list
, subst
, 0);
1304 RegQueryInfoKeyW(hkey_family
, NULL
, NULL
, NULL
, NULL
, &max_face_key_len
, NULL
, NULL
,
1305 NULL
, NULL
, NULL
, NULL
);
1307 face_name
= HeapAlloc(GetProcessHeap(), 0, (max_face_key_len
+ 1) * sizeof(WCHAR
));
1308 size
= max_face_key_len
+ 1;
1309 while(RegEnumKeyExW(hkey_family
, face_index
++, face_name
, &size
,
1310 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1314 RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
);
1315 load_face(hkey_face
, face_name
, family
);
1316 RegCloseKey(hkey_face
);
1317 size
= max_face_key_len
+ 1;
1319 HeapFree(GetProcessHeap(), 0, face_name
);
1320 RegCloseKey(hkey_family
);
1321 size
= max_family_key_len
+ 1;
1324 HeapFree(GetProcessHeap(), 0, family_name
);
1327 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1330 HKEY hkey_wine_fonts
;
1332 /* We don't want to create the fonts key as volatile, so open this first */
1333 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1334 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1335 if(ret
!= ERROR_SUCCESS
)
1337 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1341 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1342 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1343 RegCloseKey(hkey_wine_fonts
);
1347 static void add_face_to_cache(Face
*face
)
1349 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1350 WCHAR
*face_key_name
;
1352 create_font_cache_key(&hkey_font_cache
, NULL
);
1354 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1355 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1356 if(face
->family
->EnglishName
)
1357 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1358 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1361 face_key_name
= face
->StyleName
;
1364 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1365 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1366 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1368 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1371 HeapFree(GetProcessHeap(), 0, face_key_name
);
1373 RegSetValueExA(hkey_face
, "File Name", 0, REG_BINARY
, (BYTE
*)face
->file
, strlen(face
->file
) + 1);
1375 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1376 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1378 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1379 reg_save_dword(hkey_face
, face_italic_value
, (face
->ntmFlags
& NTM_ITALIC
) != 0);
1380 reg_save_dword(hkey_face
, face_bold_value
, (face
->ntmFlags
& NTM_BOLD
) != 0);
1381 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1382 reg_save_dword(hkey_face
, face_external_value
, face
->external
);
1384 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1388 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1389 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1390 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1391 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1392 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1393 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1395 RegCloseKey(hkey_face
);
1396 RegCloseKey(hkey_family
);
1397 RegCloseKey(hkey_font_cache
);
1400 /*****************************************************************
1403 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1404 * of FreeType that don't export this function.
1407 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1412 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1413 if(pFT_Load_Sfnt_Table
)
1415 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1417 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1418 else /* Do it the hard way */
1420 TT_Face tt_face
= (TT_Face
) ft_face
;
1421 SFNT_Interface
*sfnt
;
1422 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1425 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1429 /* A field was added in the middle of the structure in 2.1.x */
1430 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1432 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1440 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1441 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1442 "Please upgrade your freetype library.\n");
1445 err
= FT_Err_Unimplemented_Feature
;
1451 static inline int TestStyles(DWORD flags
, DWORD styles
)
1453 return (flags
& styles
) == styles
;
1456 static int StyleOrdering(Face
*face
)
1458 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1460 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1462 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1464 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1467 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1468 debugstr_w(face
->family
->FamilyName
),
1469 debugstr_w(face
->StyleName
),
1475 /* Add a style of face to a font family using an ordering of the list such
1476 that regular fonts come before bold and italic, and single styles come
1477 before compound styles. */
1478 static void AddFaceToFamily(Face
*face
, Family
*family
)
1482 LIST_FOR_EACH( entry
, &family
->faces
)
1484 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1485 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1487 list_add_before( entry
, &face
->entry
);
1490 #define ADDFONT_EXTERNAL_FONT 0x01
1491 #define ADDFONT_FORCE_BITMAP 0x02
1492 #define ADDFONT_ADD_TO_CACHE 0x04
1494 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1498 TT_Header
*pHeader
= NULL
;
1499 WCHAR
*english_family
, *localised_family
, *StyleW
;
1503 struct list
*family_elem_ptr
, *face_elem_ptr
;
1505 FT_Long face_index
= 0, num_faces
;
1506 #ifdef HAVE_FREETYPE_FTWINFNT_H
1507 FT_WinFNT_HeaderRec winfnt_header
;
1509 int i
, bitmap_num
, internal_leading
;
1512 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1513 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1515 #ifdef HAVE_CARBON_CARBON_H
1516 if(file
&& !fake_family
)
1518 char **mac_list
= expand_mac_font(file
);
1521 BOOL had_one
= FALSE
;
1523 for(cursor
= mac_list
; *cursor
; cursor
++)
1526 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1527 HeapFree(GetProcessHeap(), 0, *cursor
);
1529 HeapFree(GetProcessHeap(), 0, mac_list
);
1534 #endif /* HAVE_CARBON_CARBON_H */
1537 char *family_name
= fake_family
;
1541 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1542 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1545 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1546 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1550 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1554 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*/
1555 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1556 pFT_Done_Face(ft_face
);
1560 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1561 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1562 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1563 pFT_Done_Face(ft_face
);
1567 if(FT_IS_SFNT(ft_face
))
1569 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1570 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1571 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1573 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1574 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1575 pFT_Done_Face(ft_face
);
1579 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1580 we don't want to load these. */
1581 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1585 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1587 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1588 pFT_Done_Face(ft_face
);
1594 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1595 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1596 pFT_Done_Face(ft_face
);
1600 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1602 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1603 pFT_Done_Face(ft_face
);
1609 localised_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID());
1610 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1612 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1613 HeapFree(GetProcessHeap(), 0, localised_family
);
1614 num_faces
= ft_face
->num_faces
;
1615 pFT_Done_Face(ft_face
);
1618 HeapFree(GetProcessHeap(), 0, localised_family
);
1622 family_name
= ft_face
->family_name
;
1626 My_FT_Bitmap_Size
*size
= NULL
;
1629 if(!FT_IS_SCALABLE(ft_face
))
1630 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1632 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1633 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1634 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1636 localised_family
= NULL
;
1638 localised_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID());
1639 if(localised_family
&& !strcmpiW(localised_family
, english_family
)) {
1640 HeapFree(GetProcessHeap(), 0, localised_family
);
1641 localised_family
= NULL
;
1646 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1647 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1648 if(!strcmpiW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1653 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1654 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1655 family
->EnglishName
= localised_family
? strdupW(english_family
) : NULL
;
1656 list_init(&family
->faces
);
1657 list_add_tail(&font_list
, &family
->entry
);
1659 if(localised_family
) {
1660 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1661 subst
->from
.name
= strdupW(english_family
);
1662 subst
->from
.charset
= -1;
1663 subst
->to
.name
= strdupW(localised_family
);
1664 subst
->to
.charset
= -1;
1665 add_font_subst(&font_subst_list
, subst
, 0);
1668 HeapFree(GetProcessHeap(), 0, localised_family
);
1669 HeapFree(GetProcessHeap(), 0, english_family
);
1671 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1672 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1673 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1675 internal_leading
= 0;
1676 memset(&fs
, 0, sizeof(fs
));
1678 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1680 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1681 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1682 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1683 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1684 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1685 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1686 if(pOS2
->version
== 0) {
1689 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1690 fs
.fsCsb
[0] |= FS_LATIN1
;
1692 fs
.fsCsb
[0] |= FS_SYMBOL
;
1695 #ifdef HAVE_FREETYPE_FTWINFNT_H
1696 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1698 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1699 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1700 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1702 internal_leading
= winfnt_header
.internal_leading
;
1706 face_elem_ptr
= list_head(&family
->faces
);
1707 while(face_elem_ptr
) {
1708 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1709 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1710 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1711 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1712 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1713 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1714 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1717 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1718 HeapFree(GetProcessHeap(), 0, StyleW
);
1719 pFT_Done_Face(ft_face
);
1722 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1723 TRACE("Original font is newer so skipping this one\n");
1724 HeapFree(GetProcessHeap(), 0, StyleW
);
1725 pFT_Done_Face(ft_face
);
1728 TRACE("Replacing original with this one\n");
1729 list_remove(&face
->entry
);
1730 HeapFree(GetProcessHeap(), 0, face
->file
);
1731 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1732 HeapFree(GetProcessHeap(), 0, face
->FullName
);
1733 HeapFree(GetProcessHeap(), 0, face
);
1738 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1739 face
->cached_enum_data
= NULL
;
1740 face
->StyleName
= StyleW
;
1741 face
->FullName
= get_face_name(ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1744 face
->file
= strdupA(file
);
1745 face
->font_data_ptr
= NULL
;
1746 face
->font_data_size
= 0;
1751 face
->font_data_ptr
= font_data_ptr
;
1752 face
->font_data_size
= font_data_size
;
1754 face
->face_index
= face_index
;
1756 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1757 face
->ntmFlags
|= NTM_ITALIC
;
1758 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1759 face
->ntmFlags
|= NTM_BOLD
;
1760 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1761 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1762 face
->family
= family
;
1763 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1765 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1767 if(FT_IS_SCALABLE(ft_face
)) {
1768 memset(&face
->size
, 0, sizeof(face
->size
));
1769 face
->scalable
= TRUE
;
1771 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1772 size
->height
, size
->width
, size
->size
>> 6,
1773 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1774 face
->size
.height
= size
->height
;
1775 face
->size
.width
= size
->width
;
1776 face
->size
.size
= size
->size
;
1777 face
->size
.x_ppem
= size
->x_ppem
;
1778 face
->size
.y_ppem
= size
->y_ppem
;
1779 face
->size
.internal_leading
= internal_leading
;
1780 face
->scalable
= FALSE
;
1783 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1785 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1787 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1788 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1791 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1792 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1793 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1794 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1797 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1798 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1799 switch(ft_face
->charmaps
[i
]->encoding
) {
1800 case FT_ENCODING_UNICODE
:
1801 case FT_ENCODING_APPLE_ROMAN
:
1802 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1804 case FT_ENCODING_MS_SYMBOL
:
1805 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1813 if(flags
& ADDFONT_ADD_TO_CACHE
)
1814 add_face_to_cache(face
);
1816 AddFaceToFamily(face
, family
);
1818 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1820 num_faces
= ft_face
->num_faces
;
1821 pFT_Done_Face(ft_face
);
1822 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1823 debugstr_w(StyleW
));
1824 } while(num_faces
> ++face_index
);
1828 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1830 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1833 static void DumpFontList(void)
1837 struct list
*family_elem_ptr
, *face_elem_ptr
;
1839 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1840 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1841 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1842 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1843 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1844 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1846 TRACE(" %d", face
->size
.height
);
1853 /***********************************************************
1854 * The replacement list is a way to map an entire font
1855 * family onto another family. For example adding
1857 * [HKCU\Software\Wine\Fonts\Replacements]
1858 * "Wingdings"="Winedings"
1860 * would enumerate the Winedings font both as Winedings and
1861 * Wingdings. However if a real Wingdings font is present the
1862 * replacement does not take place.
1865 static void LoadReplaceList(void)
1868 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1873 struct list
*family_elem_ptr
, *face_elem_ptr
;
1876 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1877 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1879 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1880 &valuelen
, &datalen
, NULL
, NULL
);
1882 valuelen
++; /* returned value doesn't include room for '\0' */
1883 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1884 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1888 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1889 &dlen
) == ERROR_SUCCESS
) {
1890 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1891 /* "NewName"="Oldname" */
1892 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1894 if(!find_family_from_name(value
))
1896 /* Find the old family and hence all of the font files
1898 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1899 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1900 if(!strcmpiW(family
->FamilyName
, data
)) {
1901 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1902 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1903 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1904 debugstr_w(face
->StyleName
), familyA
);
1905 /* Now add a new entry with the new family name */
1906 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
,
1907 familyA
, family
->FamilyName
,
1908 ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1914 /* reset dlen and vlen */
1918 HeapFree(GetProcessHeap(), 0, data
);
1919 HeapFree(GetProcessHeap(), 0, value
);
1924 /*************************************************************
1927 static BOOL
init_system_links(void)
1931 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1932 WCHAR
*value
, *data
;
1933 WCHAR
*entry
, *next
;
1934 SYSTEM_LINKS
*font_link
, *system_font_link
;
1935 CHILD_FONT
*child_font
;
1936 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1937 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1943 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1945 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1946 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1947 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1948 val_len
= max_val
+ 1;
1949 data_len
= max_data
;
1951 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1953 memset(&fs
, 0, sizeof(fs
));
1954 psub
= get_font_subst(&font_subst_list
, value
, -1);
1955 /* Don't store fonts that are only substitutes for other fonts */
1958 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1961 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1962 font_link
->font_name
= strdupW(value
);
1963 list_init(&font_link
->links
);
1964 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1967 CHILD_FONT
*child_font
;
1969 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1971 next
= entry
+ strlenW(entry
) + 1;
1973 face_name
= strchrW(entry
, ',');
1977 while(isspaceW(*face_name
))
1980 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1982 face_name
= psub
->to
.name
;
1984 face
= find_face_from_filename(entry
, face_name
);
1987 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1991 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1992 child_font
->face
= face
;
1993 child_font
->font
= NULL
;
1994 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1995 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1996 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1997 list_add_tail(&font_link
->links
, &child_font
->entry
);
1999 family
= find_family_from_name(font_link
->font_name
);
2002 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2004 face
->fs_links
= fs
;
2007 list_add_tail(&system_links
, &font_link
->entry
);
2009 val_len
= max_val
+ 1;
2010 data_len
= max_data
;
2013 HeapFree(GetProcessHeap(), 0, value
);
2014 HeapFree(GetProcessHeap(), 0, data
);
2018 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2021 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2022 system_font_link
->font_name
= strdupW(System
);
2023 list_init(&system_font_link
->links
);
2025 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2028 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2029 child_font
->face
= face
;
2030 child_font
->font
= NULL
;
2031 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2032 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2034 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2036 if(!strcmpiW(font_link
->font_name
, Tahoma
))
2038 CHILD_FONT
*font_link_entry
;
2039 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2041 CHILD_FONT
*new_child
;
2042 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2043 new_child
->face
= font_link_entry
->face
;
2044 new_child
->font
= NULL
;
2045 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2050 list_add_tail(&system_links
, &system_font_link
->entry
);
2054 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2057 struct dirent
*dent
;
2058 char path
[MAX_PATH
];
2060 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2062 dir
= opendir(dirname
);
2064 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2067 while((dent
= readdir(dir
)) != NULL
) {
2068 struct stat statbuf
;
2070 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2073 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2075 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2077 if(stat(path
, &statbuf
) == -1)
2079 WARN("Can't stat %s\n", debugstr_a(path
));
2082 if(S_ISDIR(statbuf
.st_mode
))
2083 ReadFontDir(path
, external_fonts
);
2086 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2087 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2088 AddFontFileToList(path
, NULL
, NULL
, addfont_flags
);
2095 static void load_fontconfig_fonts(void)
2097 #ifdef SONAME_LIBFONTCONFIG
2098 void *fc_handle
= NULL
;
2107 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2109 TRACE("Wine cannot find the fontconfig library (%s).\n",
2110 SONAME_LIBFONTCONFIG
);
2113 #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;}
2114 LOAD_FUNCPTR(FcConfigGetCurrent
);
2115 LOAD_FUNCPTR(FcFontList
);
2116 LOAD_FUNCPTR(FcFontSetDestroy
);
2117 LOAD_FUNCPTR(FcInit
);
2118 LOAD_FUNCPTR(FcObjectSetAdd
);
2119 LOAD_FUNCPTR(FcObjectSetCreate
);
2120 LOAD_FUNCPTR(FcObjectSetDestroy
);
2121 LOAD_FUNCPTR(FcPatternCreate
);
2122 LOAD_FUNCPTR(FcPatternDestroy
);
2123 LOAD_FUNCPTR(FcPatternGetBool
);
2124 LOAD_FUNCPTR(FcPatternGetString
);
2127 if(!pFcInit()) return;
2129 config
= pFcConfigGetCurrent();
2130 pat
= pFcPatternCreate();
2131 os
= pFcObjectSetCreate();
2132 pFcObjectSetAdd(os
, FC_FILE
);
2133 pFcObjectSetAdd(os
, FC_SCALABLE
);
2134 fontset
= pFcFontList(config
, pat
, os
);
2135 if(!fontset
) return;
2136 for(i
= 0; i
< fontset
->nfont
; i
++) {
2139 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2141 TRACE("fontconfig: %s\n", file
);
2143 /* We're just interested in OT/TT fonts for now, so this hack just
2144 picks up the scalable fonts without extensions .pf[ab] to save time
2145 loading every other font */
2147 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2149 TRACE("not scalable\n");
2153 len
= strlen( file
);
2154 if(len
< 4) continue;
2155 ext
= &file
[ len
- 3 ];
2156 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2157 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2159 pFcFontSetDestroy(fontset
);
2160 pFcObjectSetDestroy(os
);
2161 pFcPatternDestroy(pat
);
2167 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2170 const char *data_dir
= wine_get_data_dir();
2172 if (!data_dir
) data_dir
= wine_get_build_dir();
2179 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2181 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2183 strcpy(unix_name
, data_dir
);
2184 strcat(unix_name
, "/fonts/");
2186 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2188 EnterCriticalSection( &freetype_cs
);
2189 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2190 LeaveCriticalSection( &freetype_cs
);
2191 HeapFree(GetProcessHeap(), 0, unix_name
);
2196 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2198 static const WCHAR slashW
[] = {'\\','\0'};
2200 WCHAR windowsdir
[MAX_PATH
];
2203 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2204 strcatW(windowsdir
, fontsW
);
2205 strcatW(windowsdir
, slashW
);
2206 strcatW(windowsdir
, file
);
2207 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2208 EnterCriticalSection( &freetype_cs
);
2209 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2210 LeaveCriticalSection( &freetype_cs
);
2211 HeapFree(GetProcessHeap(), 0, unixname
);
2216 static void load_system_fonts(void)
2219 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2220 const WCHAR
* const *value
;
2222 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2225 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2226 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2227 strcatW(windowsdir
, fontsW
);
2228 for(value
= SystemFontValues
; *value
; value
++) {
2229 dlen
= sizeof(data
);
2230 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2234 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2235 if((unixname
= wine_get_unix_file_name(pathW
))) {
2236 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2237 HeapFree(GetProcessHeap(), 0, unixname
);
2240 load_font_from_data_dir(data
);
2247 /*************************************************************
2249 * This adds registry entries for any externally loaded fonts
2250 * (fonts from fontconfig or FontDirs). It also deletes entries
2251 * of no longer existing fonts.
2254 static void update_reg_entries(void)
2256 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2261 struct list
*family_elem_ptr
, *face_elem_ptr
;
2263 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2264 static const WCHAR spaceW
[] = {' ', '\0'};
2267 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2268 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2269 ERR("Can't create Windows font reg key\n");
2273 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2274 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2275 ERR("Can't create Windows font reg key\n");
2279 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2280 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2281 ERR("Can't create external font reg key\n");
2285 /* enumerate the fonts and add external ones to the two keys */
2287 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2288 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2289 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2290 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2291 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2292 if(!face
->external
) continue;
2294 if (!(face
->ntmFlags
& NTM_REGULAR
))
2295 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2296 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2297 strcpyW(valueW
, family
->FamilyName
);
2298 if(len
!= len_fam
) {
2299 strcatW(valueW
, spaceW
);
2300 strcatW(valueW
, face
->StyleName
);
2302 strcatW(valueW
, TrueType
);
2304 file
= wine_get_dos_file_name(face
->file
);
2306 len
= strlenW(file
) + 1;
2309 if((path
= strrchr(face
->file
, '/')) == NULL
)
2313 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2315 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2316 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2318 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2319 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2320 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2322 HeapFree(GetProcessHeap(), 0, file
);
2323 HeapFree(GetProcessHeap(), 0, valueW
);
2327 if(external_key
) RegCloseKey(external_key
);
2328 if(win9x_key
) RegCloseKey(win9x_key
);
2329 if(winnt_key
) RegCloseKey(winnt_key
);
2333 static void delete_external_font_keys(void)
2335 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2336 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2340 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2341 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2342 ERR("Can't create Windows font reg key\n");
2346 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2347 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2348 ERR("Can't create Windows font reg key\n");
2352 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2353 ERR("Can't create external font reg key\n");
2357 /* Delete all external fonts added last time */
2359 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2360 &valuelen
, &datalen
, NULL
, NULL
);
2361 valuelen
++; /* returned value doesn't include room for '\0' */
2362 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2363 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2365 dlen
= datalen
* sizeof(WCHAR
);
2368 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2369 &dlen
) == ERROR_SUCCESS
) {
2371 RegDeleteValueW(winnt_key
, valueW
);
2372 RegDeleteValueW(win9x_key
, valueW
);
2373 /* reset dlen and vlen */
2377 HeapFree(GetProcessHeap(), 0, data
);
2378 HeapFree(GetProcessHeap(), 0, valueW
);
2380 /* Delete the old external fonts key */
2381 RegCloseKey(external_key
);
2382 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2385 if(win9x_key
) RegCloseKey(win9x_key
);
2386 if(winnt_key
) RegCloseKey(winnt_key
);
2389 /*************************************************************
2390 * WineEngAddFontResourceEx
2393 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2399 if (ft_handle
) /* do it only if we have freetype up and running */
2404 FIXME("Ignoring flags %x\n", flags
);
2406 if((unixname
= wine_get_unix_file_name(file
)))
2408 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2410 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2411 EnterCriticalSection( &freetype_cs
);
2412 ret
= AddFontFileToList(unixname
, NULL
, NULL
, addfont_flags
);
2413 LeaveCriticalSection( &freetype_cs
);
2414 HeapFree(GetProcessHeap(), 0, unixname
);
2416 if (!ret
&& !strchrW(file
, '\\')) {
2417 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2418 ret
= load_font_from_winfonts_dir(file
);
2420 /* Try in datadir/fonts (or builddir/fonts),
2421 * needed for Magic the Gathering Online
2423 ret
= load_font_from_data_dir(file
);
2430 /*************************************************************
2431 * WineEngAddFontMemResourceEx
2434 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2438 if (ft_handle
) /* do it only if we have freetype up and running */
2440 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2442 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2443 memcpy(pFontCopy
, pbFont
, cbFont
);
2445 EnterCriticalSection( &freetype_cs
);
2446 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2447 LeaveCriticalSection( &freetype_cs
);
2451 TRACE("AddFontToList failed\n");
2452 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2455 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2456 * For now return something unique but quite random
2458 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2459 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2466 /*************************************************************
2467 * WineEngRemoveFontResourceEx
2470 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2473 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2477 static const struct nls_update_font_list
2479 UINT ansi_cp
, oem_cp
;
2480 const char *oem
, *fixed
, *system
;
2481 const char *courier
, *serif
, *small
, *sserif
;
2482 /* these are for font substitutes */
2483 const char *shelldlg
, *tmsrmn
;
2484 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2488 const char *from
, *to
;
2489 } arial_0
, courier_new_0
, times_new_roman_0
;
2490 } nls_update_font_list
[] =
2492 /* Latin 1 (United States) */
2493 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2494 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2495 "Tahoma","Times New Roman",
2496 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2499 /* Latin 1 (Multilingual) */
2500 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2501 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2502 "Tahoma","Times New Roman", /* FIXME unverified */
2503 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2506 /* Eastern Europe */
2507 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2508 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2509 "Tahoma","Times New Roman", /* FIXME unverified */
2510 "Fixedsys,238", "System,238",
2511 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2512 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2513 { "Arial CE,0", "Arial,238" },
2514 { "Courier New CE,0", "Courier New,238" },
2515 { "Times New Roman CE,0", "Times New Roman,238" }
2518 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2519 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2520 "Tahoma","Times New Roman", /* FIXME unverified */
2521 "Fixedsys,204", "System,204",
2522 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2523 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2524 { "Arial Cyr,0", "Arial,204" },
2525 { "Courier New Cyr,0", "Courier New,204" },
2526 { "Times New Roman Cyr,0", "Times New Roman,204" }
2529 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2530 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2531 "Tahoma","Times New Roman", /* FIXME unverified */
2532 "Fixedsys,161", "System,161",
2533 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2534 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2535 { "Arial Greek,0", "Arial,161" },
2536 { "Courier New Greek,0", "Courier New,161" },
2537 { "Times New Roman Greek,0", "Times New Roman,161" }
2540 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2541 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2542 "Tahoma","Times New Roman", /* FIXME unverified */
2543 "Fixedsys,162", "System,162",
2544 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2545 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2546 { "Arial Tur,0", "Arial,162" },
2547 { "Courier New Tur,0", "Courier New,162" },
2548 { "Times New Roman Tur,0", "Times New Roman,162" }
2551 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2552 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2553 "Tahoma","Times New Roman", /* FIXME unverified */
2554 "Fixedsys,177", "System,177",
2555 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2556 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2560 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2561 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2562 "Tahoma","Times New Roman", /* FIXME unverified */
2563 "Fixedsys,178", "System,178",
2564 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2565 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2569 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2570 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2571 "Tahoma","Times New Roman", /* FIXME unverified */
2572 "Fixedsys,186", "System,186",
2573 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2574 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2575 { "Arial Baltic,0", "Arial,186" },
2576 { "Courier New Baltic,0", "Courier New,186" },
2577 { "Times New Roman Baltic,0", "Times New Roman,186" }
2580 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2581 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2582 "Tahoma","Times New Roman", /* FIXME unverified */
2583 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2587 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2588 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2589 "Tahoma","Times New Roman", /* FIXME unverified */
2590 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2594 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2595 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2596 "MS UI Gothic","MS Serif",
2597 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2600 /* Chinese Simplified */
2601 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2602 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2603 "SimSun", "NSimSun",
2604 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2608 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2609 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2611 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2614 /* Chinese Traditional */
2615 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2616 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2617 "PMingLiU", "MingLiU",
2618 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2623 static const WCHAR
*font_links_list
[] =
2625 Lucida_Sans_Unicode
,
2626 Microsoft_Sans_Serif
,
2630 static const struct font_links_defaults_list
2632 /* Keyed off substitution for "MS Shell Dlg" */
2633 const WCHAR
*shelldlg
;
2634 /* Maximum of four substitutes, plus terminating NULL pointer */
2635 const WCHAR
*substitutes
[5];
2636 } font_links_defaults_list
[] =
2638 /* Non East-Asian */
2639 { Tahoma
, /* FIXME unverified ordering */
2640 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2642 /* Below lists are courtesy of
2643 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2647 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2649 /* Chinese Simplified */
2651 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2655 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2657 /* Chinese Traditional */
2659 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2663 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2665 return ( ansi_cp
== 932 /* CP932 for Japanese */
2666 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2667 || ansi_cp
== 949 /* CP949 for Korean */
2668 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2671 static inline HKEY
create_fonts_NT_registry_key(void)
2675 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2676 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2680 static inline HKEY
create_fonts_9x_registry_key(void)
2684 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2685 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2689 static inline HKEY
create_config_fonts_registry_key(void)
2693 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2694 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2698 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2700 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2701 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2702 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2703 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2706 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2709 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2711 RegDeleteValueA(hkey
, name
);
2714 static void update_font_info(void)
2716 char buf
[40], cpbuf
[40];
2719 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2722 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2725 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2726 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2727 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2728 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2729 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2731 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2732 if (is_dbcs_ansi_cp(ansi_cp
))
2733 use_default_fallback
= TRUE
;
2736 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2738 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2743 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2745 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2747 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2750 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2754 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2755 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2757 hkey
= create_config_fonts_registry_key();
2758 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2759 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2760 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2763 hkey
= create_fonts_NT_registry_key();
2764 add_font_list(hkey
, &nls_update_font_list
[i
]);
2767 hkey
= create_fonts_9x_registry_key();
2768 add_font_list(hkey
, &nls_update_font_list
[i
]);
2771 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2773 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2774 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2775 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2776 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2778 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2779 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2780 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2781 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2782 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2783 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2784 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2785 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2787 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2788 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2789 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2797 /* Delete the FontSubstitutes from other locales */
2798 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2800 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2801 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2802 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2808 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2810 /* Clear out system links */
2811 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, system_link
);
2814 static void populate_system_links(HKEY hkey
, const WCHAR
*name
, const WCHAR
*const *values
)
2824 WCHAR buff
[MAX_PATH
];
2828 static const WCHAR comma
[] = {',',0};
2830 RegDeleteValueW(hkey
, name
);
2835 for (i
= 0; values
[i
] != NULL
; i
++)
2838 if (!strcmpiW(name
,value
))
2840 psub
= get_font_subst(&font_subst_list
, value
, -1);
2842 value
= psub
->to
.name
;
2843 family
= find_family_from_name(value
);
2847 /* Use first extant filename for this Family */
2848 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2852 file
= strrchr(face
->file
, '/');
2861 fileLen
= MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, NULL
, 0);
2862 fileW
= HeapAlloc(GetProcessHeap(), 0, fileLen
* sizeof(WCHAR
));
2863 MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, fileW
, fileLen
);
2864 entryLen
= strlenW(fileW
) + 1 + strlenW(value
) + 1;
2865 if (sizeof(buff
)-(data
-buff
) < entryLen
+ 1)
2867 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name
));
2868 HeapFree(GetProcessHeap(), 0, fileW
);
2871 strcpyW(data
, fileW
);
2872 strcatW(data
, comma
);
2873 strcatW(data
, value
);
2875 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2876 HeapFree(GetProcessHeap(), 0, fileW
);
2882 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (BYTE
*)buff
, (data
-buff
) * sizeof(WCHAR
));
2884 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name
));
2886 TRACE("removed SystemLink for %s\n", debugstr_w(name
));
2889 static void update_system_links(void)
2897 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2899 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE
, system_link
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, &disposition
))
2901 if (disposition
== REG_OPENED_EXISTING_KEY
)
2903 TRACE("SystemLink key already exists, doing nothing\n");
2908 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2910 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2915 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2917 if (!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
))
2919 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2920 populate_system_links(hkey
, font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2922 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2923 populate_system_links(hkey
, psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2926 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2928 populate_system_links(hkey
, font_links_defaults_list
[i
].substitutes
[0], NULL
);
2933 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub
->to
.name
));
2935 WARN("failed to create SystemLink key\n");
2939 static BOOL
init_freetype(void)
2941 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2944 "Wine cannot find the FreeType font library. To enable Wine to\n"
2945 "use TrueType fonts please install a version of FreeType greater than\n"
2946 "or equal to 2.0.5.\n"
2947 "http://www.freetype.org\n");
2951 #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;}
2953 LOAD_FUNCPTR(FT_Vector_Unit
)
2954 LOAD_FUNCPTR(FT_Done_Face
)
2955 LOAD_FUNCPTR(FT_Get_Char_Index
)
2956 LOAD_FUNCPTR(FT_Get_Module
)
2957 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2958 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2959 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2960 LOAD_FUNCPTR(FT_Init_FreeType
)
2961 LOAD_FUNCPTR(FT_Load_Glyph
)
2962 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2963 #ifndef FT_MULFIX_INLINED
2964 LOAD_FUNCPTR(FT_MulFix
)
2966 LOAD_FUNCPTR(FT_New_Face
)
2967 LOAD_FUNCPTR(FT_New_Memory_Face
)
2968 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2969 LOAD_FUNCPTR(FT_Outline_Transform
)
2970 LOAD_FUNCPTR(FT_Outline_Translate
)
2971 LOAD_FUNCPTR(FT_Select_Charmap
)
2972 LOAD_FUNCPTR(FT_Set_Charmap
)
2973 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2974 LOAD_FUNCPTR(FT_Vector_Transform
)
2975 LOAD_FUNCPTR(FT_Render_Glyph
)
2978 /* Don't warn if these ones are missing */
2979 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2980 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2981 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2982 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2983 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2984 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2985 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2987 #ifdef HAVE_FREETYPE_FTWINFNT_H
2988 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2990 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2991 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2992 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2993 <= 2.0.3 has FT_Sqrt64 */
2997 if(pFT_Init_FreeType(&library
) != 0) {
2998 ERR("Can't init FreeType library\n");
2999 wine_dlclose(ft_handle
, NULL
, 0);
3003 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
3004 if (pFT_Library_Version
)
3005 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3007 if (FT_Version
.major
<=0)
3013 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3014 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3015 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3016 ((FT_Version
.patch
) & 0x0000ff);
3022 "Wine cannot find certain functions that it needs inside the FreeType\n"
3023 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3024 "FreeType to at least version 2.0.5.\n"
3025 "http://www.freetype.org\n");
3026 wine_dlclose(ft_handle
, NULL
, 0);
3031 static void init_font_list(void)
3033 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3034 static const WCHAR pathW
[] = {'P','a','t','h',0};
3036 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3037 WCHAR windowsdir
[MAX_PATH
];
3039 const char *data_dir
;
3041 delete_external_font_keys();
3043 /* load the system bitmap fonts */
3044 load_system_fonts();
3046 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3047 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3048 strcatW(windowsdir
, fontsW
);
3049 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3051 ReadFontDir(unixname
, FALSE
);
3052 HeapFree(GetProcessHeap(), 0, unixname
);
3055 /* load the system truetype fonts */
3056 data_dir
= wine_get_data_dir();
3057 if (!data_dir
) data_dir
= wine_get_build_dir();
3058 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3060 strcpy(unixname
, data_dir
);
3061 strcat(unixname
, "/fonts/");
3062 ReadFontDir(unixname
, TRUE
);
3063 HeapFree(GetProcessHeap(), 0, unixname
);
3066 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3067 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3068 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3070 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3071 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3072 &hkey
) == ERROR_SUCCESS
)
3074 LPWSTR data
, valueW
;
3075 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3076 &valuelen
, &datalen
, NULL
, NULL
);
3078 valuelen
++; /* returned value doesn't include room for '\0' */
3079 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3080 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3083 dlen
= datalen
* sizeof(WCHAR
);
3085 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3086 &dlen
) == ERROR_SUCCESS
)
3088 if(data
[0] && (data
[1] == ':'))
3090 if((unixname
= wine_get_unix_file_name(data
)))
3092 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3093 HeapFree(GetProcessHeap(), 0, unixname
);
3096 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3098 WCHAR pathW
[MAX_PATH
];
3099 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3102 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3103 if((unixname
= wine_get_unix_file_name(pathW
)))
3105 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3106 HeapFree(GetProcessHeap(), 0, unixname
);
3109 load_font_from_data_dir(data
);
3111 /* reset dlen and vlen */
3116 HeapFree(GetProcessHeap(), 0, data
);
3117 HeapFree(GetProcessHeap(), 0, valueW
);
3121 load_fontconfig_fonts();
3123 /* then look in any directories that we've specified in the config file */
3124 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3125 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3131 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3133 len
+= sizeof(WCHAR
);
3134 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3135 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3137 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3138 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3139 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3140 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3144 LPSTR next
= strchr( ptr
, ':' );
3145 if (next
) *next
++ = 0;
3146 ReadFontDir( ptr
, TRUE
);
3149 HeapFree( GetProcessHeap(), 0, valueA
);
3151 HeapFree( GetProcessHeap(), 0, valueW
);
3157 static BOOL
move_to_front(const WCHAR
*name
)
3159 Family
*family
, *cursor2
;
3160 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3162 if(!strcmpiW(family
->FamilyName
, name
))
3164 list_remove(&family
->entry
);
3165 list_add_head(&font_list
, &family
->entry
);
3172 static const WCHAR arial
[] = {'A','r','i','a','l',0};
3173 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
3174 static const WCHAR bitstream_vera_sans_mono
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
3175 static const WCHAR bitstream_vera_serif
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
3176 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
3177 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
3179 static void reorder_font_list(void)
3181 if(!move_to_front(times_new_roman
))
3182 move_to_front(bitstream_vera_serif
);
3184 if(!move_to_front(courier_new
))
3185 move_to_front(bitstream_vera_sans_mono
);
3187 if(!move_to_front(arial
))
3188 move_to_front(bitstream_vera_sans
);
3191 /*************************************************************
3194 * Initialize FreeType library and create a list of available faces
3196 BOOL
WineEngInit(void)
3198 HKEY hkey_font_cache
;
3202 /* update locale dependent font info in registry */
3205 if(!init_freetype()) return FALSE
;
3207 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3209 ERR("Failed to create font mutex\n");
3212 WaitForSingleObject(font_mutex
, INFINITE
);
3214 create_font_cache_key(&hkey_font_cache
, &disposition
);
3216 if(disposition
== REG_CREATED_NEW_KEY
)
3219 load_font_list_from_cache(hkey_font_cache
);
3221 RegCloseKey(hkey_font_cache
);
3223 reorder_font_list();
3230 if(disposition
== REG_CREATED_NEW_KEY
)
3231 update_reg_entries();
3233 update_system_links();
3234 init_system_links();
3236 ReleaseMutex(font_mutex
);
3241 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3244 TT_HoriHeader
*pHori
;
3248 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3249 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3251 if(height
== 0) height
= 16;
3253 /* Calc. height of EM square:
3255 * For +ve lfHeight we have
3256 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3257 * Re-arranging gives:
3258 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3260 * For -ve lfHeight we have
3262 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3263 * with il = winAscent + winDescent - units_per_em]
3268 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3269 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3270 pHori
->Ascender
- pHori
->Descender
);
3272 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3273 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3281 static struct font_mapping
*map_font_file( const char *name
)
3283 struct font_mapping
*mapping
;
3287 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3288 if (fstat( fd
, &st
) == -1) goto error
;
3290 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3292 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3294 mapping
->refcount
++;
3299 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3302 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3305 if (mapping
->data
== MAP_FAILED
)
3307 HeapFree( GetProcessHeap(), 0, mapping
);
3310 mapping
->refcount
= 1;
3311 mapping
->dev
= st
.st_dev
;
3312 mapping
->ino
= st
.st_ino
;
3313 mapping
->size
= st
.st_size
;
3314 list_add_tail( &mappings_list
, &mapping
->entry
);
3322 static void unmap_font_file( struct font_mapping
*mapping
)
3324 if (!--mapping
->refcount
)
3326 list_remove( &mapping
->entry
);
3327 munmap( mapping
->data
, mapping
->size
);
3328 HeapFree( GetProcessHeap(), 0, mapping
);
3332 static LONG
load_VDMX(GdiFont
*, LONG
);
3334 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3341 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3345 if (!(font
->mapping
= map_font_file( face
->file
)))
3347 WARN("failed to map %s\n", debugstr_a(face
->file
));
3350 data_ptr
= font
->mapping
->data
;
3351 data_size
= font
->mapping
->size
;
3355 data_ptr
= face
->font_data_ptr
;
3356 data_size
= face
->font_data_size
;
3359 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3361 ERR("FT_New_Face rets %d\n", err
);
3365 /* set it here, as load_VDMX needs it */
3366 font
->ft_face
= ft_face
;
3368 if(FT_IS_SCALABLE(ft_face
)) {
3369 /* load the VDMX table if we have one */
3370 font
->ppem
= load_VDMX(font
, height
);
3372 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3373 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3375 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3376 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3378 font
->ppem
= height
;
3379 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3380 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3386 static int get_nearest_charset(Face
*face
, int *cp
)
3388 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3389 a single face with the requested charset. The idea is to check if
3390 the selected font supports the current ANSI codepage, if it does
3391 return the corresponding charset, else return the first charset */
3394 int acp
= GetACP(), i
;
3398 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3399 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3400 return csi
.ciCharset
;
3402 for(i
= 0; i
< 32; i
++) {
3404 if(face
->fs
.fsCsb
[0] & fs0
) {
3405 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3407 return csi
.ciCharset
;
3410 FIXME("TCI failing on %x\n", fs0
);
3414 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3415 face
->fs
.fsCsb
[0], face
->file
);
3417 return DEFAULT_CHARSET
;
3420 static GdiFont
*alloc_font(void)
3422 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3424 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3425 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3427 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3428 ret
->total_kern_pairs
= (DWORD
)-1;
3429 ret
->kern_pairs
= NULL
;
3430 list_init(&ret
->hfontlist
);
3431 list_init(&ret
->child_fonts
);
3435 static void free_font(GdiFont
*font
)
3437 struct list
*cursor
, *cursor2
;
3440 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3442 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3443 list_remove(cursor
);
3445 free_font(child
->font
);
3446 HeapFree(GetProcessHeap(), 0, child
);
3449 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3451 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3452 DeleteObject(hfontlist
->hfont
);
3453 list_remove(&hfontlist
->entry
);
3454 HeapFree(GetProcessHeap(), 0, hfontlist
);
3457 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3458 if (font
->mapping
) unmap_font_file( font
->mapping
);
3459 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3460 HeapFree(GetProcessHeap(), 0, font
->potm
);
3461 HeapFree(GetProcessHeap(), 0, font
->name
);
3462 for (i
= 0; i
< font
->gmsize
; i
++)
3463 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3464 HeapFree(GetProcessHeap(), 0, font
->gm
);
3465 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3466 HeapFree(GetProcessHeap(), 0, font
);
3470 /*************************************************************
3473 * load the vdmx entry for the specified height
3476 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3477 ( ( (FT_ULong)_x4 << 24 ) | \
3478 ( (FT_ULong)_x3 << 16 ) | \
3479 ( (FT_ULong)_x2 << 8 ) | \
3482 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3497 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3501 BYTE devXRatio
, devYRatio
;
3502 USHORT numRecs
, numRatios
;
3503 DWORD result
, offset
= -1;
3507 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3509 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3512 /* FIXME: need the real device aspect ratio */
3516 numRecs
= GET_BE_WORD(hdr
[1]);
3517 numRatios
= GET_BE_WORD(hdr
[2]);
3519 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3520 for(i
= 0; i
< numRatios
; i
++) {
3523 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3524 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3527 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3529 if((ratio
.xRatio
== 0 &&
3530 ratio
.yStartRatio
== 0 &&
3531 ratio
.yEndRatio
== 0) ||
3532 (devXRatio
== ratio
.xRatio
&&
3533 devYRatio
>= ratio
.yStartRatio
&&
3534 devYRatio
<= ratio
.yEndRatio
))
3536 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3537 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3538 offset
= GET_BE_WORD(tmp
);
3544 FIXME("No suitable ratio found\n");
3548 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3550 BYTE startsz
, endsz
;
3553 recs
= GET_BE_WORD(group
.recs
);
3554 startsz
= group
.startsz
;
3555 endsz
= group
.endsz
;
3557 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3559 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3560 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3561 if(result
== GDI_ERROR
) {
3562 FIXME("Failed to retrieve vTable\n");
3567 for(i
= 0; i
< recs
; i
++) {
3568 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3569 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3570 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3572 if(yMax
+ -yMin
== height
) {
3575 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3578 if(yMax
+ -yMin
> height
) {
3581 goto end
; /* failed */
3583 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3584 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3585 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3586 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3592 TRACE("ppem not found for height %d\n", height
);
3596 HeapFree(GetProcessHeap(), 0, vTable
);
3602 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3604 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3605 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3606 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3607 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3608 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3611 static void calc_hash(FONT_DESC
*pfd
)
3613 DWORD hash
= 0, *ptr
, two_chars
;
3617 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3619 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3621 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3623 pwc
= (WCHAR
*)&two_chars
;
3625 *pwc
= toupperW(*pwc
);
3627 *pwc
= toupperW(*pwc
);
3631 hash
^= !pfd
->can_use_bitmap
;
3636 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3641 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3645 fd
.can_use_bitmap
= can_use_bitmap
;
3648 /* try the child list */
3649 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3650 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3651 if(!fontcmp(ret
, &fd
)) {
3652 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3653 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3654 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3655 if(hflist
->hfont
== hfont
)
3661 /* try the in-use list */
3662 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3663 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3664 if(!fontcmp(ret
, &fd
)) {
3665 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3666 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3667 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3668 if(hflist
->hfont
== hfont
)
3671 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3672 hflist
->hfont
= hfont
;
3673 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3678 /* then the unused list */
3679 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3680 while(font_elem_ptr
) {
3681 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3682 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3683 if(!fontcmp(ret
, &fd
)) {
3684 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3685 assert(list_empty(&ret
->hfontlist
));
3686 TRACE("Found %p in unused list\n", ret
);
3687 list_remove(&ret
->entry
);
3688 list_add_head(&gdi_font_list
, &ret
->entry
);
3689 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3690 hflist
->hfont
= hfont
;
3691 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3698 static void add_to_cache(GdiFont
*font
)
3700 static DWORD cache_num
= 1;
3702 font
->cache_num
= cache_num
++;
3703 list_add_head(&gdi_font_list
, &font
->entry
);
3706 /*************************************************************
3707 * create_child_font_list
3709 static BOOL
create_child_font_list(GdiFont
*font
)
3712 SYSTEM_LINKS
*font_link
;
3713 CHILD_FONT
*font_link_entry
, *new_child
;
3717 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3718 font_name
= psub
? psub
->to
.name
: font
->name
;
3719 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3721 if(!strcmpiW(font_link
->font_name
, font_name
))
3723 TRACE("found entry in system list\n");
3724 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3726 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3727 new_child
->face
= font_link_entry
->face
;
3728 new_child
->font
= NULL
;
3729 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3730 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3737 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3738 * Sans Serif. This is how asian windows get default fallbacks for fonts
3740 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3741 font
->charset
!= OEM_CHARSET
&&
3742 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3743 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3745 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3747 TRACE("found entry in default fallback list\n");
3748 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3750 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3751 new_child
->face
= font_link_entry
->face
;
3752 new_child
->font
= NULL
;
3753 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3754 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3764 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3766 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3768 if (pFT_Set_Charmap
)
3771 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3773 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3775 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3777 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3779 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3780 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3782 switch (ft_face
->charmaps
[i
]->platform_id
)
3785 cmap_def
= ft_face
->charmaps
[i
];
3787 case 0: /* Apple Unicode */
3788 cmap0
= ft_face
->charmaps
[i
];
3790 case 1: /* Macintosh */
3791 cmap1
= ft_face
->charmaps
[i
];
3794 cmap2
= ft_face
->charmaps
[i
];
3796 case 3: /* Microsoft */
3797 cmap3
= ft_face
->charmaps
[i
];
3802 if (cmap3
) /* prefer Microsoft cmap table */
3803 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3805 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3807 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3809 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3811 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3813 return ft_err
== FT_Err_Ok
;
3816 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3819 /*************************************************************
3820 * WineEngCreateFontInstance
3823 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3826 Face
*face
, *best
, *best_bitmap
;
3827 Family
*family
, *last_resort_family
;
3828 struct list
*family_elem_ptr
, *face_elem_ptr
;
3829 INT height
, width
= 0;
3830 unsigned int score
= 0, new_score
;
3831 signed int diff
= 0, newdiff
;
3832 BOOL bd
, it
, can_use_bitmap
;
3837 FontSubst
*psub
= NULL
;
3839 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3840 lf
.lfWidth
= abs(lf
.lfWidth
);
3842 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3844 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3845 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3846 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3849 if(dc
->GraphicsMode
== GM_ADVANCED
)
3850 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3853 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3854 font scaling abilities. */
3855 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3856 dcmat
.eM21
= dcmat
.eM12
= 0;
3859 /* Try to avoid not necessary glyph transformations */
3860 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3862 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3863 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3864 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3867 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3868 dcmat
.eM21
, dcmat
.eM22
);
3871 EnterCriticalSection( &freetype_cs
);
3873 /* check the cache first */
3874 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3875 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3876 LeaveCriticalSection( &freetype_cs
);
3880 TRACE("not in cache\n");
3881 if(list_empty(&font_list
)) /* No fonts installed */
3883 TRACE("No fonts installed\n");
3884 LeaveCriticalSection( &freetype_cs
);
3890 ret
->font_desc
.matrix
= dcmat
;
3891 ret
->font_desc
.lf
= lf
;
3892 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3893 calc_hash(&ret
->font_desc
);
3894 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3895 hflist
->hfont
= hfont
;
3896 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3898 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3899 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3900 original value lfCharSet. Note this is a special case for
3901 Symbol and doesn't happen at least for "Wingdings*" */
3903 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3904 lf
.lfCharSet
= SYMBOL_CHARSET
;
3906 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3907 switch(lf
.lfCharSet
) {
3908 case DEFAULT_CHARSET
:
3909 csi
.fs
.fsCsb
[0] = 0;
3912 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3913 csi
.fs
.fsCsb
[0] = 0;
3919 if(lf
.lfFaceName
[0] != '\0') {
3920 SYSTEM_LINKS
*font_link
;
3921 CHILD_FONT
*font_link_entry
;
3922 LPWSTR FaceName
= lf
.lfFaceName
;
3925 * Check for a leading '@' this signals that the font is being
3926 * requested in tategaki mode (vertical writing substitution) but
3927 * does not affect the fontface that is to be selected.
3929 if (lf
.lfFaceName
[0]=='@')
3930 FaceName
= &lf
.lfFaceName
[1];
3932 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3935 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3936 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3937 if (psub
->to
.charset
!= -1)
3938 lf
.lfCharSet
= psub
->to
.charset
;
3941 /* We want a match on name and charset or just name if
3942 charset was DEFAULT_CHARSET. If the latter then
3943 we fixup the returned charset later in get_nearest_charset
3944 where we'll either use the charset of the current ansi codepage
3945 or if that's unavailable the first charset that the font supports.
3947 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3948 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3949 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3950 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3952 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3953 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3954 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3955 if(face
->scalable
|| can_use_bitmap
)
3961 /* Search by full face name. */
3962 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3963 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3964 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3965 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3966 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
3967 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]))
3969 if(face
->scalable
|| can_use_bitmap
)
3976 * Try check the SystemLink list first for a replacement font.
3977 * We may find good replacements there.
3979 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3981 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3982 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3984 TRACE("found entry in system list\n");
3985 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3987 face
= font_link_entry
->face
;
3988 family
= face
->family
;
3989 if(csi
.fs
.fsCsb
[0] &
3990 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3992 if(face
->scalable
|| can_use_bitmap
)
4000 psub
= NULL
; /* substitution is no more relevant */
4002 /* If requested charset was DEFAULT_CHARSET then try using charset
4003 corresponding to the current ansi codepage */
4004 if (!csi
.fs
.fsCsb
[0])
4007 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4008 FIXME("TCI failed on codepage %d\n", acp
);
4009 csi
.fs
.fsCsb
[0] = 0;
4011 lf
.lfCharSet
= csi
.ciCharset
;
4014 /* Face families are in the top 4 bits of lfPitchAndFamily,
4015 so mask with 0xF0 before testing */
4017 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4018 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4019 strcpyW(lf
.lfFaceName
, defFixed
);
4020 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4021 strcpyW(lf
.lfFaceName
, defSerif
);
4022 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4023 strcpyW(lf
.lfFaceName
, defSans
);
4025 strcpyW(lf
.lfFaceName
, defSans
);
4026 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4027 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4028 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4029 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4030 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4031 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
4032 if(face
->scalable
|| can_use_bitmap
)
4038 last_resort_family
= NULL
;
4039 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4040 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4041 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4042 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4043 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
4046 if(can_use_bitmap
&& !last_resort_family
)
4047 last_resort_family
= family
;
4052 if(last_resort_family
) {
4053 family
= last_resort_family
;
4054 csi
.fs
.fsCsb
[0] = 0;
4058 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4059 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4060 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4061 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4062 if(face
->scalable
) {
4063 csi
.fs
.fsCsb
[0] = 0;
4064 WARN("just using first face for now\n");
4067 if(can_use_bitmap
&& !last_resort_family
)
4068 last_resort_family
= family
;
4071 if(!last_resort_family
) {
4072 FIXME("can't find a single appropriate font - bailing\n");
4074 LeaveCriticalSection( &freetype_cs
);
4078 WARN("could only find a bitmap font - this will probably look awful!\n");
4079 family
= last_resort_family
;
4080 csi
.fs
.fsCsb
[0] = 0;
4083 it
= lf
.lfItalic
? 1 : 0;
4084 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4086 height
= lf
.lfHeight
;
4088 face
= best
= best_bitmap
= NULL
;
4089 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
4091 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
4095 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4096 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4097 new_score
= (italic
^ it
) + (bold
^ bd
);
4098 if(!best
|| new_score
<= score
)
4100 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4101 italic
, bold
, it
, bd
);
4104 if(best
->scalable
&& score
== 0) break;
4108 newdiff
= height
- (signed int)(best
->size
.height
);
4110 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4111 if(!best_bitmap
|| new_score
< score
||
4112 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4114 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4117 if(score
== 0 && diff
== 0) break;
4124 face
= best
->scalable
? best
: best_bitmap
;
4125 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4126 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4129 height
= lf
.lfHeight
;
4133 if(csi
.fs
.fsCsb
[0]) {
4134 ret
->charset
= lf
.lfCharSet
;
4135 ret
->codepage
= csi
.ciACP
;
4138 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
4140 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4141 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4143 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4145 if(!face
->scalable
) {
4146 /* Windows uses integer scaling factors for bitmap fonts */
4147 INT scale
, scaled_height
;
4148 GdiFont
*cachedfont
;
4150 /* FIXME: rotation of bitmap fonts is ignored */
4151 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4153 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4154 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4155 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4156 /* As we changed the matrix, we need to search the cache for the font again,
4157 * otherwise we might explode the cache. */
4158 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4159 TRACE("Found cached font after non-scalable matrix rescale!\n");
4161 LeaveCriticalSection( &freetype_cs
);
4164 calc_hash(&ret
->font_desc
);
4166 if (height
!= 0) height
= diff
;
4167 height
+= face
->size
.height
;
4169 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4170 scaled_height
= scale
* face
->size
.height
;
4171 /* Only jump to the next height if the difference <= 25% original height */
4172 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4173 /* The jump between unscaled and doubled is delayed by 1 */
4174 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4175 ret
->scale_y
= scale
;
4177 width
= face
->size
.x_ppem
>> 6;
4178 height
= face
->size
.y_ppem
>> 6;
4182 TRACE("font scale y: %f\n", ret
->scale_y
);
4184 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4189 LeaveCriticalSection( &freetype_cs
);
4193 ret
->ntmFlags
= face
->ntmFlags
;
4195 if (ret
->charset
== SYMBOL_CHARSET
&&
4196 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4199 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4203 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4206 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4207 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4208 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4209 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4210 create_child_font_list(ret
);
4212 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
4214 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
4215 if (length
!= GDI_ERROR
)
4217 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4218 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4219 TRACE("Loaded GSUB table of %i bytes\n",length
);
4223 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4226 LeaveCriticalSection( &freetype_cs
);
4230 static void dump_gdi_font_list(void)
4233 struct list
*elem_ptr
;
4235 TRACE("---------- gdiFont Cache ----------\n");
4236 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4237 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4238 TRACE("gdiFont=%p %s %d\n",
4239 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4242 TRACE("---------- Unused gdiFont Cache ----------\n");
4243 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4244 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4245 TRACE("gdiFont=%p %s %d\n",
4246 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4249 TRACE("---------- Child gdiFont Cache ----------\n");
4250 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4251 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4252 TRACE("gdiFont=%p %s %d\n",
4253 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4257 /*************************************************************
4258 * WineEngDestroyFontInstance
4260 * free the gdiFont associated with this handle
4263 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4268 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4272 EnterCriticalSection( &freetype_cs
);
4274 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4276 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4277 while(hfontlist_elem_ptr
) {
4278 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4279 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4280 if(hflist
->hfont
== handle
) {
4281 TRACE("removing child font %p from child list\n", gdiFont
);
4282 list_remove(&gdiFont
->entry
);
4283 LeaveCriticalSection( &freetype_cs
);
4289 TRACE("destroying hfont=%p\n", handle
);
4291 dump_gdi_font_list();
4293 font_elem_ptr
= list_head(&gdi_font_list
);
4294 while(font_elem_ptr
) {
4295 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4296 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4298 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4299 while(hfontlist_elem_ptr
) {
4300 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4301 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4302 if(hflist
->hfont
== handle
) {
4303 list_remove(&hflist
->entry
);
4304 HeapFree(GetProcessHeap(), 0, hflist
);
4308 if(list_empty(&gdiFont
->hfontlist
)) {
4309 TRACE("Moving to Unused list\n");
4310 list_remove(&gdiFont
->entry
);
4311 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4316 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4317 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4318 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4319 while(font_elem_ptr
) {
4320 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4321 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4322 TRACE("freeing %p\n", gdiFont
);
4323 list_remove(&gdiFont
->entry
);
4326 LeaveCriticalSection( &freetype_cs
);
4330 /***************************************************
4331 * create_enum_charset_list
4333 * This function creates charset enumeration list because in DEFAULT_CHARSET
4334 * case, the ANSI codepage's charset takes precedence over other charsets.
4335 * This function works as a filter other than DEFAULT_CHARSET case.
4337 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4342 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4343 csi
.fs
.fsCsb
[0] != 0) {
4344 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4345 list
->element
[n
].charset
= csi
.ciCharset
;
4346 list
->element
[n
].name
= ElfScriptsW
[ffs(csi
.fs
.fsCsb
[0]) - 1];
4349 else { /* charset is DEFAULT_CHARSET or invalid. */
4352 /* Set the current codepage's charset as the first element. */
4354 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4355 csi
.fs
.fsCsb
[0] != 0) {
4356 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4357 list
->element
[n
].charset
= csi
.ciCharset
;
4358 list
->element
[n
].name
= ElfScriptsW
[ffs(csi
.fs
.fsCsb
[0]) - 1];
4362 /* Fill out left elements. */
4363 for (i
= 0; i
< 32; i
++) {
4365 fs
.fsCsb
[0] = 1L << i
;
4367 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4368 continue; /* skip, already added. */
4369 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4370 continue; /* skip, this is an invalid fsCsb bit. */
4372 list
->element
[n
].mask
= fs
.fsCsb
[0];
4373 list
->element
[n
].charset
= csi
.ciCharset
;
4374 list
->element
[n
].name
= ElfScriptsW
[i
];
4383 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4384 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4389 if (face
->cached_enum_data
)
4392 *pelf
= face
->cached_enum_data
->elf
;
4393 *pntm
= face
->cached_enum_data
->ntm
;
4394 *ptype
= face
->cached_enum_data
->type
;
4398 font
= alloc_font();
4400 if(face
->scalable
) {
4401 height
= -2048; /* 2048 is the most common em size */
4404 height
= face
->size
.y_ppem
>> 6;
4405 width
= face
->size
.x_ppem
>> 6;
4407 font
->scale_y
= 1.0;
4409 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4415 font
->name
= strdupW(face
->family
->FamilyName
);
4416 font
->ntmFlags
= face
->ntmFlags
;
4418 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4420 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4422 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4424 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4425 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4427 lstrcpynW(pelf
->elfFullName
,
4428 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4430 lstrcpynW(pelf
->elfStyle
,
4431 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4436 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4438 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4440 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4442 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4444 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4445 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4448 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4449 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4450 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4451 pntm
->ntmFontSig
= face
->fs
;
4453 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4455 pelf
->elfLogFont
.lfEscapement
= 0;
4456 pelf
->elfLogFont
.lfOrientation
= 0;
4457 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4458 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4459 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4460 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4461 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4462 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4463 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4464 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4465 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4466 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4467 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4470 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4471 *ptype
|= TRUETYPE_FONTTYPE
;
4472 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4473 *ptype
|= DEVICE_FONTTYPE
;
4474 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4475 *ptype
|= RASTER_FONTTYPE
;
4477 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4478 if (face
->cached_enum_data
)
4480 face
->cached_enum_data
->elf
= *pelf
;
4481 face
->cached_enum_data
->ntm
= *pntm
;
4482 face
->cached_enum_data
->type
= *ptype
;
4488 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4490 struct list
*face_elem_ptr
;
4492 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4494 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
)
4496 static const WCHAR spaceW
[] = { ' ',0 };
4497 WCHAR full_family_name
[LF_FULLFACESIZE
];
4498 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4500 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4502 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4503 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4507 strcpyW(full_family_name
, family
->FamilyName
);
4508 strcatW(full_family_name
, spaceW
);
4509 strcatW(full_family_name
, face
->StyleName
);
4510 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4516 static BOOL
face_matches(Face
*face
, const LOGFONTW
*lf
)
4518 static const WCHAR spaceW
[] = { ' ',0 };
4519 WCHAR full_family_name
[LF_FULLFACESIZE
];
4521 if (!strcmpiW(lf
->lfFaceName
, face
->family
->FamilyName
)) return TRUE
;
4523 if (strlenW(face
->family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4525 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4526 debugstr_w(face
->family
->FamilyName
), debugstr_w(face
->StyleName
));
4530 strcpyW(full_family_name
, face
->family
->FamilyName
);
4531 strcatW(full_family_name
, spaceW
);
4532 strcatW(full_family_name
, face
->StyleName
);
4533 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4536 static BOOL
enum_face_charsets(Face
*face
, struct enum_charset_list
*list
,
4537 FONTENUMPROCW proc
, LPARAM lparam
)
4540 NEWTEXTMETRICEXW ntm
;
4544 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4545 for(i
= 0; i
< list
->total
; i
++) {
4546 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4547 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4548 strcpyW(elf
.elfScript
, OEM_DOSW
);
4549 i
= 32; /* break out of loop */
4550 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4553 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4554 if(list
->element
[i
].name
)
4555 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4557 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4559 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4560 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4561 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4562 list
->element
[i
].charset
, type
, debugstr_w(elf
.elfScript
),
4563 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4564 ntm
.ntmTm
.ntmFlags
);
4565 /* release section before callback (FIXME) */
4566 LeaveCriticalSection( &freetype_cs
);
4567 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4568 EnterCriticalSection( &freetype_cs
);
4573 /*************************************************************
4577 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4581 struct list
*family_elem_ptr
, *face_elem_ptr
;
4583 struct enum_charset_list enum_charsets
;
4587 lf
.lfCharSet
= DEFAULT_CHARSET
;
4588 lf
.lfPitchAndFamily
= 0;
4589 lf
.lfFaceName
[0] = 0;
4593 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4595 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4598 EnterCriticalSection( &freetype_cs
);
4599 if(plf
->lfFaceName
[0]) {
4601 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4604 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4605 debugstr_w(psub
->to
.name
));
4607 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4611 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4612 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4613 if(family_matches(family
, plf
)) {
4614 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4615 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4616 if (!face_matches(face
, plf
)) continue;
4617 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return 0;
4622 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4623 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4624 face_elem_ptr
= list_head(&family
->faces
);
4625 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4626 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return 0;
4629 LeaveCriticalSection( &freetype_cs
);
4633 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4635 pt
->x
.value
= vec
->x
>> 6;
4636 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4637 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4638 pt
->y
.value
= vec
->y
>> 6;
4639 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4640 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4644 /***************************************************
4645 * According to the MSDN documentation on WideCharToMultiByte,
4646 * certain codepages cannot set the default_used parameter.
4647 * This returns TRUE if the codepage can set that parameter, false else
4648 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4650 static BOOL
codepage_sets_default_used(UINT codepage
)
4664 * GSUB Table handling functions
4667 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4669 const GSUB_CoverageFormat1
* cf1
;
4673 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4675 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4677 TRACE("Coverage Format 1, %i glyphs\n",count
);
4678 for (i
= 0; i
< count
; i
++)
4679 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4683 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4685 const GSUB_CoverageFormat2
* cf2
;
4688 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4690 count
= GET_BE_WORD(cf2
->RangeCount
);
4691 TRACE("Coverage Format 2, %i ranges\n",count
);
4692 for (i
= 0; i
< count
; i
++)
4694 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4696 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4697 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4699 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4700 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4706 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4711 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4713 const GSUB_ScriptList
*script
;
4714 const GSUB_Script
*deflt
= NULL
;
4716 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4718 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4719 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4721 const GSUB_Script
*scr
;
4724 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4725 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4727 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4729 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4735 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4739 const GSUB_LangSys
*Lang
;
4741 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4743 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4745 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4746 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4748 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4751 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4754 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4760 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4763 const GSUB_FeatureList
*feature
;
4764 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4766 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4767 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4769 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4770 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4772 const GSUB_Feature
*feat
;
4773 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4780 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4784 const GSUB_LookupList
*lookup
;
4785 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4787 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4788 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4790 const GSUB_LookupTable
*look
;
4791 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4792 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4793 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4794 if (GET_BE_WORD(look
->LookupType
) != 1)
4795 FIXME("We only handle SubType 1\n");
4800 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4802 const GSUB_SingleSubstFormat1
*ssf1
;
4803 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4804 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4805 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4807 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4808 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4809 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4811 TRACE(" Glyph 0x%x ->",glyph
);
4812 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4813 TRACE(" 0x%x\n",glyph
);
4818 const GSUB_SingleSubstFormat2
*ssf2
;
4822 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4823 offset
= GET_BE_WORD(ssf1
->Coverage
);
4824 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4825 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4826 TRACE(" Coverage index %i\n",index
);
4829 TRACE(" Glyph is 0x%x ->",glyph
);
4830 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4831 TRACE("0x%x\n",glyph
);
4840 static const char* get_opentype_script(const GdiFont
*font
)
4843 * I am not sure if this is the correct way to generate our script tag
4846 switch (font
->charset
)
4848 case ANSI_CHARSET
: return "latn";
4849 case BALTIC_CHARSET
: return "latn"; /* ?? */
4850 case CHINESEBIG5_CHARSET
: return "hani";
4851 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4852 case GB2312_CHARSET
: return "hani";
4853 case GREEK_CHARSET
: return "grek";
4854 case HANGUL_CHARSET
: return "hang";
4855 case RUSSIAN_CHARSET
: return "cyrl";
4856 case SHIFTJIS_CHARSET
: return "kana";
4857 case TURKISH_CHARSET
: return "latn"; /* ?? */
4858 case VIETNAMESE_CHARSET
: return "latn";
4859 case JOHAB_CHARSET
: return "latn"; /* ?? */
4860 case ARABIC_CHARSET
: return "arab";
4861 case HEBREW_CHARSET
: return "hebr";
4862 case THAI_CHARSET
: return "thai";
4863 default: return "latn";
4867 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4869 const GSUB_Header
*header
;
4870 const GSUB_Script
*script
;
4871 const GSUB_LangSys
*language
;
4872 const GSUB_Feature
*feature
;
4874 if (!font
->GSUB_Table
)
4877 header
= font
->GSUB_Table
;
4879 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4882 TRACE("Script not found\n");
4885 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4888 TRACE("Language not found\n");
4891 feature
= GSUB_get_feature(header
, language
, "vrt2");
4893 feature
= GSUB_get_feature(header
, language
, "vert");
4896 TRACE("vrt2/vert feature not found\n");
4899 return GSUB_apply_feature(header
, feature
, glyph
);
4902 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4906 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4907 WCHAR wc
= (WCHAR
)glyph
;
4909 BOOL
*default_used_pointer
;
4912 default_used_pointer
= NULL
;
4913 default_used
= FALSE
;
4914 if (codepage_sets_default_used(font
->codepage
))
4915 default_used_pointer
= &default_used
;
4916 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4919 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4920 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4921 return get_GSUB_vert_glyph(font
,ret
);
4924 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
4926 if (glyph
< 0x100) glyph
+= 0xf000;
4927 /* there is a number of old pre-Unicode "broken" TTFs, which
4928 do have symbols at U+00XX instead of U+f0XX */
4929 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
4930 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
4932 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4934 return get_GSUB_vert_glyph(font
,glyphId
);
4937 /*************************************************************
4938 * WineEngGetGlyphIndices
4941 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4942 LPWORD pgi
, DWORD flags
)
4946 BOOL got_default
= FALSE
;
4948 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
4950 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4954 for(i
= 0; i
< count
; i
++)
4956 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4961 if (FT_IS_SFNT(font
->ft_face
))
4963 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4964 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4969 WineEngGetTextMetrics(font
, &textm
);
4970 default_char
= textm
.tmDefaultChar
;
4974 pgi
[i
] = default_char
;
4980 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4982 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4983 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4986 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4988 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4989 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4992 /*************************************************************
4993 * WineEngGetGlyphOutline
4995 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4996 * except that the first parameter is the HWINEENGFONT of the font in
4997 * question rather than an HDC.
5000 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5001 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5004 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5005 FT_Face ft_face
= incoming_font
->ft_face
;
5006 GdiFont
*font
= incoming_font
;
5007 FT_UInt glyph_index
;
5008 DWORD width
, height
, pitch
, needed
= 0;
5009 FT_Bitmap ft_bitmap
;
5011 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5013 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5014 double widthRatio
= 1.0;
5015 FT_Matrix transMat
= identityMat
;
5016 FT_Matrix transMatUnrotated
;
5017 BOOL needsTransform
= FALSE
;
5018 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5019 UINT original_index
;
5021 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5022 buflen
, buf
, lpmat
);
5024 TRACE("font transform %f %f %f %f\n",
5025 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5026 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5029 EnterCriticalSection( &freetype_cs
);
5031 if(format
& GGO_GLYPH_INDEX
) {
5032 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5033 original_index
= glyph
;
5034 format
&= ~GGO_GLYPH_INDEX
;
5036 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5037 ft_face
= font
->ft_face
;
5038 original_index
= glyph_index
;
5041 if(format
& GGO_UNHINTED
) {
5042 load_flags
|= FT_LOAD_NO_HINTING
;
5043 format
&= ~GGO_UNHINTED
;
5046 /* tategaki never appears to happen to lower glyph index */
5047 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5050 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5051 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5052 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5053 font
->gmsize
* sizeof(GM
*));
5055 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5056 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5058 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5059 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5060 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5061 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5062 LeaveCriticalSection( &freetype_cs
);
5063 return 1; /* FIXME */
5067 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5068 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5070 /* Scaling factor */
5075 WineEngGetTextMetrics(font
, &tm
);
5077 widthRatio
= (double)font
->aveWidth
;
5078 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5081 widthRatio
= font
->scale_y
;
5083 /* Scaling transform */
5084 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5087 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5090 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5092 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5093 needsTransform
= TRUE
;
5096 /* Slant transform */
5097 if (font
->fake_italic
) {
5100 slantMat
.xx
= (1 << 16);
5101 slantMat
.xy
= ((1 << 16) >> 2);
5103 slantMat
.yy
= (1 << 16);
5104 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5105 needsTransform
= TRUE
;
5108 /* Rotation transform */
5109 transMatUnrotated
= transMat
;
5110 if(font
->orientation
&& !tategaki
) {
5111 FT_Matrix rotationMat
;
5113 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5114 pFT_Vector_Unit(&vecAngle
, angle
);
5115 rotationMat
.xx
= vecAngle
.x
;
5116 rotationMat
.xy
= -vecAngle
.y
;
5117 rotationMat
.yx
= -rotationMat
.xy
;
5118 rotationMat
.yy
= rotationMat
.xx
;
5120 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5121 needsTransform
= TRUE
;
5124 /* World transform */
5125 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5128 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5129 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5130 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5131 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5132 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5133 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5134 needsTransform
= TRUE
;
5137 /* Extra transformation specified by caller */
5138 if (!is_identity_MAT2(lpmat
))
5141 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5142 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5143 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5144 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5145 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5146 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5147 needsTransform
= TRUE
;
5150 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5151 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5152 format
== GGO_GRAY8_BITMAP
))
5154 load_flags
|= FT_LOAD_NO_BITMAP
;
5157 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5160 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5161 LeaveCriticalSection( &freetype_cs
);
5165 if(!needsTransform
) {
5166 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5167 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5168 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5170 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5171 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5172 ft_face
->glyph
->metrics
.height
) & -64;
5173 lpgm
->gmCellIncX
= adv
;
5174 lpgm
->gmCellIncY
= 0;
5181 for(xc
= 0; xc
< 2; xc
++) {
5182 for(yc
= 0; yc
< 2; yc
++) {
5183 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5184 xc
* ft_face
->glyph
->metrics
.width
);
5185 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5186 yc
* ft_face
->glyph
->metrics
.height
;
5187 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5188 pFT_Vector_Transform(&vec
, &transMat
);
5189 if(xc
== 0 && yc
== 0) {
5190 left
= right
= vec
.x
;
5191 top
= bottom
= vec
.y
;
5193 if(vec
.x
< left
) left
= vec
.x
;
5194 else if(vec
.x
> right
) right
= vec
.x
;
5195 if(vec
.y
< bottom
) bottom
= vec
.y
;
5196 else if(vec
.y
> top
) top
= vec
.y
;
5201 right
= (right
+ 63) & -64;
5202 bottom
= bottom
& -64;
5203 top
= (top
+ 63) & -64;
5205 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5206 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5208 pFT_Vector_Transform(&vec
, &transMat
);
5209 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5210 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5212 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5214 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5215 adv
= (vec
.x
+63) >> 6;
5219 bbx
= (right
- left
) >> 6;
5220 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5221 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5222 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5223 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5225 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5226 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5227 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5229 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5230 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5232 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5233 FONT_GM(font
,original_index
)->adv
= adv
;
5234 FONT_GM(font
,original_index
)->lsb
= lsb
;
5235 FONT_GM(font
,original_index
)->bbx
= bbx
;
5236 FONT_GM(font
,original_index
)->init
= TRUE
;
5239 if(format
== GGO_METRICS
)
5241 LeaveCriticalSection( &freetype_cs
);
5242 return 1; /* FIXME */
5245 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5246 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5247 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5248 format
== GGO_GRAY8_BITMAP
))
5250 TRACE("loaded a bitmap\n");
5251 LeaveCriticalSection( &freetype_cs
);
5257 width
= lpgm
->gmBlackBoxX
;
5258 height
= lpgm
->gmBlackBoxY
;
5259 pitch
= ((width
+ 31) >> 5) << 2;
5260 needed
= pitch
* height
;
5262 if(!buf
|| !buflen
) break;
5264 switch(ft_face
->glyph
->format
) {
5265 case ft_glyph_format_bitmap
:
5267 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5268 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5269 INT h
= ft_face
->glyph
->bitmap
.rows
;
5271 memcpy(dst
, src
, w
);
5272 src
+= ft_face
->glyph
->bitmap
.pitch
;
5278 case ft_glyph_format_outline
:
5279 ft_bitmap
.width
= width
;
5280 ft_bitmap
.rows
= height
;
5281 ft_bitmap
.pitch
= pitch
;
5282 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5283 ft_bitmap
.buffer
= buf
;
5286 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5288 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5290 /* Note: FreeType will only set 'black' bits for us. */
5291 memset(buf
, 0, needed
);
5292 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5296 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5297 LeaveCriticalSection( &freetype_cs
);
5302 case GGO_GRAY2_BITMAP
:
5303 case GGO_GRAY4_BITMAP
:
5304 case GGO_GRAY8_BITMAP
:
5305 case WINE_GGO_GRAY16_BITMAP
:
5307 unsigned int mult
, row
, col
;
5310 width
= lpgm
->gmBlackBoxX
;
5311 height
= lpgm
->gmBlackBoxY
;
5312 pitch
= (width
+ 3) / 4 * 4;
5313 needed
= pitch
* height
;
5315 if(!buf
|| !buflen
) break;
5317 switch(ft_face
->glyph
->format
) {
5318 case ft_glyph_format_bitmap
:
5320 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5321 INT h
= ft_face
->glyph
->bitmap
.rows
;
5323 memset( buf
, 0, needed
);
5325 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5326 if (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) dst
[x
] = 0xff;
5327 src
+= ft_face
->glyph
->bitmap
.pitch
;
5330 LeaveCriticalSection( &freetype_cs
);
5333 case ft_glyph_format_outline
:
5335 ft_bitmap
.width
= width
;
5336 ft_bitmap
.rows
= height
;
5337 ft_bitmap
.pitch
= pitch
;
5338 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5339 ft_bitmap
.buffer
= buf
;
5342 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5344 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5346 memset(ft_bitmap
.buffer
, 0, buflen
);
5348 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5350 if(format
== GGO_GRAY2_BITMAP
)
5352 else if(format
== GGO_GRAY4_BITMAP
)
5354 else if(format
== GGO_GRAY8_BITMAP
)
5356 else /* format == WINE_GGO_GRAY16_BITMAP */
5358 LeaveCriticalSection( &freetype_cs
);
5364 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5365 LeaveCriticalSection( &freetype_cs
);
5370 for(row
= 0; row
< height
; row
++) {
5372 for(col
= 0; col
< width
; col
++, ptr
++) {
5373 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
5380 case WINE_GGO_HRGB_BITMAP
:
5381 case WINE_GGO_HBGR_BITMAP
:
5382 case WINE_GGO_VRGB_BITMAP
:
5383 case WINE_GGO_VBGR_BITMAP
:
5384 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5386 switch (ft_face
->glyph
->format
)
5388 case FT_GLYPH_FORMAT_BITMAP
:
5393 width
= lpgm
->gmBlackBoxX
;
5394 height
= lpgm
->gmBlackBoxY
;
5396 needed
= pitch
* height
;
5398 if (!buf
|| !buflen
) break;
5400 memset(buf
, 0, buflen
);
5402 src
= ft_face
->glyph
->bitmap
.buffer
;
5403 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5405 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5408 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5410 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
5411 ((unsigned int *)dst
)[x
] = ~0u;
5420 case FT_GLYPH_FORMAT_OUTLINE
:
5424 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5425 INT x_shift
, y_shift
;
5427 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5428 FT_Render_Mode render_mode
=
5429 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5430 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5432 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5434 if ( render_mode
== FT_RENDER_MODE_LCD
)
5436 lpgm
->gmBlackBoxX
+= 2;
5437 lpgm
->gmptGlyphOrigin
.x
-= 1;
5441 lpgm
->gmBlackBoxY
+= 2;
5442 lpgm
->gmptGlyphOrigin
.y
+= 1;
5446 width
= lpgm
->gmBlackBoxX
;
5447 height
= lpgm
->gmBlackBoxY
;
5449 needed
= pitch
* height
;
5451 if (!buf
|| !buflen
) break;
5453 memset(buf
, 0, buflen
);
5455 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5457 if ( needsTransform
)
5458 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5460 if ( pFT_Library_SetLcdFilter
)
5461 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5462 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5464 src
= ft_face
->glyph
->bitmap
.buffer
;
5465 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5466 src_width
= ft_face
->glyph
->bitmap
.width
;
5467 src_height
= ft_face
->glyph
->bitmap
.rows
;
5469 if ( render_mode
== FT_RENDER_MODE_LCD
)
5477 rgb_interval
= src_pitch
;
5482 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5483 if ( x_shift
< 0 ) x_shift
= 0;
5484 if ( x_shift
+ (src_width
/ hmul
) > width
)
5485 x_shift
= width
- (src_width
/ hmul
);
5487 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5488 if ( y_shift
< 0 ) y_shift
= 0;
5489 if ( y_shift
+ (src_height
/ vmul
) > height
)
5490 y_shift
= height
- (src_height
/ vmul
);
5492 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5493 while ( src_height
)
5495 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5499 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5500 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5501 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5502 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5506 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5507 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5508 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5509 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5512 src
+= src_pitch
* vmul
;
5521 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5522 LeaveCriticalSection ( &freetype_cs
);
5529 LeaveCriticalSection( &freetype_cs
);
5535 int contour
, point
= 0, first_pt
;
5536 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5537 TTPOLYGONHEADER
*pph
;
5539 DWORD pph_start
, cpfx
, type
;
5541 if(buflen
== 0) buf
= NULL
;
5543 if (needsTransform
&& buf
) {
5544 pFT_Outline_Transform(outline
, &transMat
);
5547 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5549 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5552 pph
->dwType
= TT_POLYGON_TYPE
;
5553 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5555 needed
+= sizeof(*pph
);
5557 while(point
<= outline
->contours
[contour
]) {
5558 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5559 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5560 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5564 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5567 } while(point
<= outline
->contours
[contour
] &&
5568 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5569 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5570 /* At the end of a contour Windows adds the start point, but
5572 if(point
> outline
->contours
[contour
] &&
5573 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5575 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5577 } else if(point
<= outline
->contours
[contour
] &&
5578 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5579 /* add closing pt for bezier */
5581 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5589 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5592 pph
->cb
= needed
- pph_start
;
5598 /* Convert the quadratic Beziers to cubic Beziers.
5599 The parametric eqn for a cubic Bezier is, from PLRM:
5600 r(t) = at^3 + bt^2 + ct + r0
5601 with the control points:
5606 A quadratic Bezier has the form:
5607 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5609 So equating powers of t leads to:
5610 r1 = 2/3 p1 + 1/3 p0
5611 r2 = 2/3 p1 + 1/3 p2
5612 and of course r0 = p0, r3 = p2
5615 int contour
, point
= 0, first_pt
;
5616 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5617 TTPOLYGONHEADER
*pph
;
5619 DWORD pph_start
, cpfx
, type
;
5620 FT_Vector cubic_control
[4];
5621 if(buflen
== 0) buf
= NULL
;
5623 if (needsTransform
&& buf
) {
5624 pFT_Outline_Transform(outline
, &transMat
);
5627 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5629 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5632 pph
->dwType
= TT_POLYGON_TYPE
;
5633 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5635 needed
+= sizeof(*pph
);
5637 while(point
<= outline
->contours
[contour
]) {
5638 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5639 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5640 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5643 if(type
== TT_PRIM_LINE
) {
5645 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5649 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5652 /* FIXME: Possible optimization in endpoint calculation
5653 if there are two consecutive curves */
5654 cubic_control
[0] = outline
->points
[point
-1];
5655 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5656 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5657 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5658 cubic_control
[0].x
>>= 1;
5659 cubic_control
[0].y
>>= 1;
5661 if(point
+1 > outline
->contours
[contour
])
5662 cubic_control
[3] = outline
->points
[first_pt
];
5664 cubic_control
[3] = outline
->points
[point
+1];
5665 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5666 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5667 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5668 cubic_control
[3].x
>>= 1;
5669 cubic_control
[3].y
>>= 1;
5672 /* r1 = 1/3 p0 + 2/3 p1
5673 r2 = 1/3 p2 + 2/3 p1 */
5674 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5675 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5676 cubic_control
[2] = cubic_control
[1];
5677 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5678 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5679 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5680 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5682 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5683 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5684 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5689 } while(point
<= outline
->contours
[contour
] &&
5690 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5691 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5692 /* At the end of a contour Windows adds the start point,
5693 but only for Beziers and we've already done that.
5695 if(point
<= outline
->contours
[contour
] &&
5696 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5697 /* This is the closing pt of a bezier, but we've already
5698 added it, so just inc point and carry on */
5705 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5708 pph
->cb
= needed
- pph_start
;
5714 FIXME("Unsupported format %d\n", format
);
5715 LeaveCriticalSection( &freetype_cs
);
5718 LeaveCriticalSection( &freetype_cs
);
5722 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5724 FT_Face ft_face
= font
->ft_face
;
5725 #ifdef HAVE_FREETYPE_FTWINFNT_H
5726 FT_WinFNT_HeaderRec winfnt_header
;
5728 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5729 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5730 font
->potm
->otmSize
= size
;
5732 #define TM font->potm->otmTextMetrics
5733 #ifdef HAVE_FREETYPE_FTWINFNT_H
5734 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5736 TM
.tmHeight
= winfnt_header
.pixel_height
;
5737 TM
.tmAscent
= winfnt_header
.ascent
;
5738 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5739 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5740 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5741 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5742 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5743 TM
.tmWeight
= winfnt_header
.weight
;
5745 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5746 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5747 TM
.tmFirstChar
= winfnt_header
.first_char
;
5748 TM
.tmLastChar
= winfnt_header
.last_char
;
5749 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5750 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5751 TM
.tmItalic
= winfnt_header
.italic
;
5752 TM
.tmUnderlined
= font
->underline
;
5753 TM
.tmStruckOut
= font
->strikeout
;
5754 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5755 TM
.tmCharSet
= winfnt_header
.charset
;
5760 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5761 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5762 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5763 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5764 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5765 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5766 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5767 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5769 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5770 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5772 TM
.tmLastChar
= 255;
5773 TM
.tmDefaultChar
= 32;
5774 TM
.tmBreakChar
= 32;
5775 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5776 TM
.tmUnderlined
= font
->underline
;
5777 TM
.tmStruckOut
= font
->strikeout
;
5778 /* NB inverted meaning of TMPF_FIXED_PITCH */
5779 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5780 TM
.tmCharSet
= font
->charset
;
5788 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5790 double scale_x
, scale_y
;
5794 scale_x
= (double)font
->aveWidth
;
5795 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5798 scale_x
= font
->scale_y
;
5800 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5801 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5803 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5804 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5806 SCALE_Y(ptm
->tmHeight
);
5807 SCALE_Y(ptm
->tmAscent
);
5808 SCALE_Y(ptm
->tmDescent
);
5809 SCALE_Y(ptm
->tmInternalLeading
);
5810 SCALE_Y(ptm
->tmExternalLeading
);
5811 SCALE_Y(ptm
->tmOverhang
);
5813 SCALE_X(ptm
->tmAveCharWidth
);
5814 SCALE_X(ptm
->tmMaxCharWidth
);
5820 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5822 double scale_x
, scale_y
;
5826 scale_x
= (double)font
->aveWidth
;
5827 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5830 scale_x
= font
->scale_y
;
5832 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5833 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5835 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5837 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5838 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5840 SCALE_Y(potm
->otmAscent
);
5841 SCALE_Y(potm
->otmDescent
);
5842 SCALE_Y(potm
->otmLineGap
);
5843 SCALE_Y(potm
->otmsCapEmHeight
);
5844 SCALE_Y(potm
->otmsXHeight
);
5845 SCALE_Y(potm
->otmrcFontBox
.top
);
5846 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5847 SCALE_X(potm
->otmrcFontBox
.left
);
5848 SCALE_X(potm
->otmrcFontBox
.right
);
5849 SCALE_Y(potm
->otmMacAscent
);
5850 SCALE_Y(potm
->otmMacDescent
);
5851 SCALE_Y(potm
->otmMacLineGap
);
5852 SCALE_X(potm
->otmptSubscriptSize
.x
);
5853 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5854 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5855 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5856 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5857 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5858 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5859 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5860 SCALE_Y(potm
->otmsStrikeoutSize
);
5861 SCALE_Y(potm
->otmsStrikeoutPosition
);
5862 SCALE_Y(potm
->otmsUnderscoreSize
);
5863 SCALE_Y(potm
->otmsUnderscorePosition
);
5869 /*************************************************************
5870 * WineEngGetTextMetrics
5873 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5876 EnterCriticalSection( &freetype_cs
);
5878 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5879 if(!get_bitmap_text_metrics(font
))
5881 LeaveCriticalSection( &freetype_cs
);
5885 /* Make sure that the font has sane width/height ratio */
5888 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
5890 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
5896 *ptm
= font
->potm
->otmTextMetrics
;
5897 scale_font_metrics(font
, ptm
);
5898 LeaveCriticalSection( &freetype_cs
);
5902 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5906 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5908 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
5914 /*************************************************************
5915 * WineEngGetOutlineTextMetrics
5918 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5919 OUTLINETEXTMETRICW
*potm
)
5921 FT_Face ft_face
= font
->ft_face
;
5922 UINT needed
, lenfam
, lensty
, ret
;
5924 TT_HoriHeader
*pHori
;
5925 TT_Postscript
*pPost
;
5926 FT_Fixed x_scale
, y_scale
;
5927 WCHAR
*family_nameW
, *style_nameW
;
5928 static const WCHAR spaceW
[] = {' ', '\0'};
5930 INT ascent
, descent
;
5932 TRACE("font=%p\n", font
);
5934 if(!FT_IS_SCALABLE(ft_face
))
5938 EnterCriticalSection( &freetype_cs
);
5941 if(cbSize
>= font
->potm
->otmSize
)
5943 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5944 scale_outline_font_metrics(font
, potm
);
5946 LeaveCriticalSection( &freetype_cs
);
5947 return font
->potm
->otmSize
;
5951 needed
= sizeof(*potm
);
5953 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5954 family_nameW
= strdupW(font
->name
);
5956 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5958 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5959 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5960 style_nameW
, lensty
/sizeof(WCHAR
));
5962 /* These names should be read from the TT name table */
5964 /* length of otmpFamilyName */
5967 /* length of otmpFaceName */
5968 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5969 needed
+= lenfam
; /* just the family name */
5971 needed
+= lenfam
+ lensty
; /* family + " " + style */
5974 /* length of otmpStyleName */
5977 /* length of otmpFullName */
5978 needed
+= lenfam
+ lensty
;
5981 x_scale
= ft_face
->size
->metrics
.x_scale
;
5982 y_scale
= ft_face
->size
->metrics
.y_scale
;
5984 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5986 FIXME("Can't find OS/2 table - not TT font?\n");
5991 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5993 FIXME("Can't find HHEA table - not TT font?\n");
5998 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6000 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",
6001 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6002 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6003 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6004 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6005 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6007 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6008 font
->potm
->otmSize
= needed
;
6010 #define TM font->potm->otmTextMetrics
6012 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6013 ascent
= pHori
->Ascender
;
6014 descent
= -pHori
->Descender
;
6016 ascent
= pOS2
->usWinAscent
;
6017 descent
= pOS2
->usWinDescent
;
6021 TM
.tmAscent
= font
->yMax
;
6022 TM
.tmDescent
= -font
->yMin
;
6023 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6025 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6026 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6027 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6028 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6031 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6034 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6036 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6037 ((ascent
+ descent
) -
6038 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6040 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6041 if (TM
.tmAveCharWidth
== 0) {
6042 TM
.tmAveCharWidth
= 1;
6044 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6045 TM
.tmWeight
= FW_REGULAR
;
6046 if (font
->fake_bold
)
6047 TM
.tmWeight
= FW_BOLD
;
6050 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6052 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6053 TM
.tmWeight
= pOS2
->usWeightClass
;
6055 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6056 TM
.tmWeight
= pOS2
->usWeightClass
;
6059 TM
.tmDigitizedAspectX
= 300;
6060 TM
.tmDigitizedAspectY
= 300;
6061 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6062 * symbol range to 0 - f0ff
6065 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6070 case 1257: /* Baltic */
6071 TM
.tmLastChar
= 0xf8fd;
6074 TM
.tmLastChar
= 0xf0ff;
6076 TM
.tmBreakChar
= 0x20;
6077 TM
.tmDefaultChar
= 0x1f;
6081 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6082 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6084 if(pOS2
->usFirstCharIndex
<= 1)
6085 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6086 else if (pOS2
->usFirstCharIndex
> 0xff)
6087 TM
.tmBreakChar
= 0x20;
6089 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6090 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6092 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6093 TM
.tmUnderlined
= font
->underline
;
6094 TM
.tmStruckOut
= font
->strikeout
;
6096 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6097 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6098 (pOS2
->version
== 0xFFFFU
||
6099 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6100 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6102 TM
.tmPitchAndFamily
= 0;
6104 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6106 case PAN_FAMILY_SCRIPT
:
6107 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6110 case PAN_FAMILY_DECORATIVE
:
6111 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6116 case PAN_FAMILY_TEXT_DISPLAY
:
6117 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6118 /* which is clearly not what the panose spec says. */
6120 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6121 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6122 TM
.tmPitchAndFamily
= FF_MODERN
;
6125 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6130 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6133 case PAN_SERIF_COVE
:
6134 case PAN_SERIF_OBTUSE_COVE
:
6135 case PAN_SERIF_SQUARE_COVE
:
6136 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6137 case PAN_SERIF_SQUARE
:
6138 case PAN_SERIF_THIN
:
6139 case PAN_SERIF_BONE
:
6140 case PAN_SERIF_EXAGGERATED
:
6141 case PAN_SERIF_TRIANGLE
:
6142 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6145 case PAN_SERIF_NORMAL_SANS
:
6146 case PAN_SERIF_OBTUSE_SANS
:
6147 case PAN_SERIF_PERP_SANS
:
6148 case PAN_SERIF_FLARED
:
6149 case PAN_SERIF_ROUNDED
:
6150 TM
.tmPitchAndFamily
|= FF_SWISS
;
6157 if(FT_IS_SCALABLE(ft_face
))
6158 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6160 if(FT_IS_SFNT(ft_face
))
6162 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6163 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6165 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6168 TM
.tmCharSet
= font
->charset
;
6170 font
->potm
->otmFiller
= 0;
6171 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6172 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6173 font
->potm
->otmfsType
= pOS2
->fsType
;
6174 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6175 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6176 font
->potm
->otmItalicAngle
= 0; /* POST table */
6177 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6178 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6179 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6180 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6181 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6182 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6183 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6184 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6185 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6186 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6187 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6188 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6189 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6190 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6191 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6192 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6193 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6194 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6195 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6196 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6197 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6198 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6199 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6200 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6202 font
->potm
->otmsUnderscoreSize
= 0;
6203 font
->potm
->otmsUnderscorePosition
= 0;
6205 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6206 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6210 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6211 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6212 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6213 strcpyW((WCHAR
*)cp
, family_nameW
);
6215 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6216 strcpyW((WCHAR
*)cp
, style_nameW
);
6218 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6219 strcpyW((WCHAR
*)cp
, family_nameW
);
6220 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6221 strcatW((WCHAR
*)cp
, spaceW
);
6222 strcatW((WCHAR
*)cp
, style_nameW
);
6223 cp
+= lenfam
+ lensty
;
6226 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6227 strcpyW((WCHAR
*)cp
, family_nameW
);
6228 strcatW((WCHAR
*)cp
, spaceW
);
6229 strcatW((WCHAR
*)cp
, style_nameW
);
6232 if(potm
&& needed
<= cbSize
)
6234 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
6235 scale_outline_font_metrics(font
, potm
);
6239 HeapFree(GetProcessHeap(), 0, style_nameW
);
6240 HeapFree(GetProcessHeap(), 0, family_nameW
);
6242 LeaveCriticalSection( &freetype_cs
);
6246 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6248 HFONTLIST
*hfontlist
;
6249 child
->font
= alloc_font();
6250 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6251 if(!child
->font
->ft_face
)
6253 free_font(child
->font
);
6258 child
->font
->font_desc
= font
->font_desc
;
6259 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6260 child
->font
->orientation
= font
->orientation
;
6261 child
->font
->scale_y
= font
->scale_y
;
6262 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6263 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6264 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6265 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6266 child
->font
->base_font
= font
;
6267 list_add_head(&child_font_list
, &child
->font
->entry
);
6268 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6272 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6275 CHILD_FONT
*child_font
;
6278 font
= font
->base_font
;
6280 *linked_font
= font
;
6282 if((*glyph
= get_glyph_index(font
, c
)))
6285 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6287 if(!child_font
->font
)
6288 if(!load_child_font(font
, child_font
))
6291 if(!child_font
->font
->ft_face
)
6293 g
= get_glyph_index(child_font
->font
, c
);
6297 *linked_font
= child_font
->font
;
6304 /*************************************************************
6305 * WineEngGetCharWidth
6308 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6311 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6314 FT_UInt glyph_index
;
6315 GdiFont
*linked_font
;
6317 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
6320 EnterCriticalSection( &freetype_cs
);
6321 for(c
= firstChar
; c
<= lastChar
; c
++) {
6322 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
6323 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6324 &gm
, 0, NULL
, &identity
);
6325 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6327 LeaveCriticalSection( &freetype_cs
);
6331 /*************************************************************
6332 * WineEngGetCharABCWidths
6335 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6338 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6341 FT_UInt glyph_index
;
6342 GdiFont
*linked_font
;
6344 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
6346 if(!FT_IS_SCALABLE(font
->ft_face
))
6350 EnterCriticalSection( &freetype_cs
);
6352 for(c
= firstChar
; c
<= lastChar
; c
++) {
6353 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
6354 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6355 &gm
, 0, NULL
, &identity
);
6356 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6357 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6358 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6359 FONT_GM(linked_font
,glyph_index
)->bbx
;
6361 LeaveCriticalSection( &freetype_cs
);
6365 /*************************************************************
6366 * WineEngGetCharABCWidthsFloat
6369 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
6371 static const MAT2 identity
= {{0,1}, {0,0}, {0,0}, {0,1}};
6374 FT_UInt glyph_index
;
6375 GdiFont
*linked_font
;
6377 TRACE("%p, %d, %d, %p\n", font
, first
, last
, buffer
);
6380 EnterCriticalSection( &freetype_cs
);
6382 for (c
= first
; c
<= last
; c
++)
6384 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
6385 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6386 &gm
, 0, NULL
, &identity
);
6387 buffer
[c
- first
].abcfA
= FONT_GM(linked_font
, glyph_index
)->lsb
;
6388 buffer
[c
- first
].abcfB
= FONT_GM(linked_font
, glyph_index
)->bbx
;
6389 buffer
[c
- first
].abcfC
= FONT_GM(linked_font
, glyph_index
)->adv
-
6390 FONT_GM(linked_font
, glyph_index
)->lsb
-
6391 FONT_GM(linked_font
, glyph_index
)->bbx
;
6393 LeaveCriticalSection( &freetype_cs
);
6397 /*************************************************************
6398 * WineEngGetCharABCWidthsI
6401 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6404 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6407 FT_UInt glyph_index
;
6408 GdiFont
*linked_font
;
6410 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
6414 EnterCriticalSection( &freetype_cs
);
6416 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
6418 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6419 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6420 &gm
, 0, NULL
, &identity
);
6421 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6422 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6423 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6424 - FONT_GM(linked_font
,c
)->bbx
;
6427 for(c
= 0; c
< count
; c
++) {
6428 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6429 &gm
, 0, NULL
, &identity
);
6430 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6431 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6432 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6433 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6436 LeaveCriticalSection( &freetype_cs
);
6440 /*************************************************************
6441 * WineEngGetTextExtentExPoint
6444 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6445 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6447 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6452 FT_UInt glyph_index
;
6453 GdiFont
*linked_font
;
6455 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
6459 EnterCriticalSection( &freetype_cs
);
6462 WineEngGetTextMetrics(font
, &tm
);
6463 size
->cy
= tm
.tmHeight
;
6465 for(idx
= 0; idx
< count
; idx
++) {
6466 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
6467 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6468 &gm
, 0, NULL
, &identity
);
6469 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6471 if (! pnfit
|| ext
<= max_ext
) {
6481 LeaveCriticalSection( &freetype_cs
);
6482 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6486 /*************************************************************
6487 * WineEngGetTextExtentExPointI
6490 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6491 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6493 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6499 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
6502 EnterCriticalSection( &freetype_cs
);
6505 WineEngGetTextMetrics(font
, &tm
);
6506 size
->cy
= tm
.tmHeight
;
6508 for(idx
= 0; idx
< count
; idx
++) {
6509 WineEngGetGlyphOutline(font
, indices
[idx
],
6510 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
6512 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
6514 if (! pnfit
|| ext
<= max_ext
) {
6524 LeaveCriticalSection( &freetype_cs
);
6525 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6529 /*************************************************************
6530 * WineEngGetFontData
6533 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6536 FT_Face ft_face
= font
->ft_face
;
6540 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6541 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6542 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6544 if(!FT_IS_SFNT(ft_face
))
6552 if(table
) { /* MS tags differ in endianness from FT ones */
6553 table
= table
>> 24 | table
<< 24 |
6554 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
6557 /* make sure value of len is the value freetype says it needs */
6560 FT_ULong needed
= 0;
6561 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
6562 if( !err
&& needed
< len
) len
= needed
;
6564 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
6567 TRACE("Can't find table %c%c%c%c\n",
6568 /* bytes were reversed */
6569 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
6570 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
6576 /*************************************************************
6577 * WineEngGetTextFace
6580 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6582 INT n
= strlenW(font
->name
) + 1;
6584 lstrcpynW(str
, font
->name
, count
);
6585 return min(count
, n
);
6590 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6592 if (fs
) *fs
= font
->fs
;
6593 return font
->charset
;
6596 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6598 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6599 struct list
*first_hfont
;
6603 EnterCriticalSection( &freetype_cs
);
6604 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6605 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6606 if(font
== linked_font
)
6607 *new_hfont
= dc
->hFont
;
6610 first_hfont
= list_head(&linked_font
->hfontlist
);
6611 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6613 LeaveCriticalSection( &freetype_cs
);
6617 /* Retrieve a list of supported Unicode ranges for a given font.
6618 * Can be called with NULL gs to calculate the buffer size. Returns
6619 * the number of ranges found.
6621 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6623 DWORD num_ranges
= 0;
6625 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6628 FT_ULong char_code
, char_code_prev
;
6631 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6633 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6634 face
->num_glyphs
, glyph_code
, char_code
);
6636 if (!glyph_code
) return 0;
6640 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6641 gs
->ranges
[0].cGlyphs
= 0;
6642 gs
->cGlyphsSupported
= 0;
6648 if (char_code
< char_code_prev
)
6650 ERR("expected increasing char code from FT_Get_Next_Char\n");
6653 if (char_code
- char_code_prev
> 1)
6658 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6659 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6660 gs
->cGlyphsSupported
++;
6665 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6666 gs
->cGlyphsSupported
++;
6668 char_code_prev
= char_code
;
6669 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6673 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6678 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6681 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
6683 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6686 glyphset
->cbThis
= size
;
6687 glyphset
->cRanges
= num_ranges
;
6688 glyphset
->flAccel
= 0;
6693 /*************************************************************
6696 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6700 EnterCriticalSection( &freetype_cs
);
6701 ret
= !list_empty(&font
->child_fonts
);
6702 LeaveCriticalSection( &freetype_cs
);
6706 static BOOL
is_hinting_enabled(void)
6708 /* Use the >= 2.2.0 function if available */
6709 if(pFT_Get_TrueType_Engine_Type
)
6711 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6712 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6714 #ifdef FT_DRIVER_HAS_HINTER
6719 /* otherwise if we've been compiled with < 2.2.0 headers
6720 use the internal macro */
6721 mod
= pFT_Get_Module(library
, "truetype");
6722 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6730 static BOOL
is_subpixel_rendering_enabled( void )
6732 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6733 return pFT_Library_SetLcdFilter
&&
6734 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6740 /*************************************************************************
6741 * GetRasterizerCaps (GDI32.@)
6743 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6745 static int hinting
= -1;
6746 static int subpixel
= -1;
6750 hinting
= is_hinting_enabled();
6751 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6754 if ( subpixel
== -1 )
6756 subpixel
= is_subpixel_rendering_enabled();
6757 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6760 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6761 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6763 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6764 lprs
->nLanguageID
= 0;
6768 /*************************************************************
6769 * WineEngRealizationInfo
6771 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6773 FIXME("(%p, %p): stub!\n", font
, info
);
6776 if(FT_IS_SCALABLE(font
->ft_face
))
6779 info
->cache_num
= font
->cache_num
;
6780 info
->unknown2
= -1;
6784 /*************************************************************************
6785 * Kerning support for TrueType fonts
6787 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6789 struct TT_kern_table
6795 struct TT_kern_subtable
6804 USHORT horizontal
: 1;
6806 USHORT cross_stream
: 1;
6807 USHORT override
: 1;
6808 USHORT reserved1
: 4;
6814 struct TT_format0_kern_subtable
6818 USHORT entrySelector
;
6829 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6830 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6831 const USHORT
*glyph_to_char
,
6832 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6835 const struct TT_kern_pair
*tt_kern_pair
;
6837 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6839 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6841 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6842 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6843 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6845 if (!kern_pair
|| !cPairs
)
6848 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6850 nPairs
= min(nPairs
, cPairs
);
6852 for (i
= 0; i
< nPairs
; i
++)
6854 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6855 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6856 /* this algorithm appears to better match what Windows does */
6857 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6858 if (kern_pair
->iKernAmount
< 0)
6860 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6861 kern_pair
->iKernAmount
-= font
->ppem
;
6863 else if (kern_pair
->iKernAmount
> 0)
6865 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6866 kern_pair
->iKernAmount
+= font
->ppem
;
6868 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6870 TRACE("left %u right %u value %d\n",
6871 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6875 TRACE("copied %u entries\n", nPairs
);
6879 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6883 const struct TT_kern_table
*tt_kern_table
;
6884 const struct TT_kern_subtable
*tt_kern_subtable
;
6886 USHORT
*glyph_to_char
;
6889 EnterCriticalSection( &freetype_cs
);
6890 if (font
->total_kern_pairs
!= (DWORD
)-1)
6892 if (cPairs
&& kern_pair
)
6894 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6895 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6896 LeaveCriticalSection( &freetype_cs
);
6899 LeaveCriticalSection( &freetype_cs
);
6900 return font
->total_kern_pairs
;
6903 font
->total_kern_pairs
= 0;
6905 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6907 if (length
== GDI_ERROR
)
6909 TRACE("no kerning data in the font\n");
6910 LeaveCriticalSection( &freetype_cs
);
6914 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6917 WARN("Out of memory\n");
6918 LeaveCriticalSection( &freetype_cs
);
6922 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6924 /* build a glyph index to char code map */
6925 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6928 WARN("Out of memory allocating a glyph index to char code map\n");
6929 HeapFree(GetProcessHeap(), 0, buf
);
6930 LeaveCriticalSection( &freetype_cs
);
6934 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6940 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6942 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6943 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6947 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6949 /* FIXME: This doesn't match what Windows does: it does some fancy
6950 * things with duplicate glyph index to char code mappings, while
6951 * we just avoid overriding existing entries.
6953 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6954 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6956 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6963 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6964 for (n
= 0; n
<= 65535; n
++)
6965 glyph_to_char
[n
] = (USHORT
)n
;
6968 tt_kern_table
= buf
;
6969 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6970 TRACE("version %u, nTables %u\n",
6971 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6973 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6975 for (i
= 0; i
< nTables
; i
++)
6977 struct TT_kern_subtable tt_kern_subtable_copy
;
6979 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6980 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6981 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6983 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6984 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6985 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6987 /* According to the TrueType specification this is the only format
6988 * that will be properly interpreted by Windows and OS/2
6990 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6992 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6994 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6995 glyph_to_char
, NULL
, 0);
6996 font
->total_kern_pairs
+= new_chunk
;
6998 if (!font
->kern_pairs
)
6999 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7000 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7002 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7003 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7005 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7006 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7009 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7011 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7014 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7015 HeapFree(GetProcessHeap(), 0, buf
);
7017 if (cPairs
&& kern_pair
)
7019 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7020 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7021 LeaveCriticalSection( &freetype_cs
);
7024 LeaveCriticalSection( &freetype_cs
);
7025 return font
->total_kern_pairs
;
7028 #else /* HAVE_FREETYPE */
7030 /*************************************************************************/
7032 BOOL
WineEngInit(void)
7036 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
7040 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7045 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
7050 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
7051 LPWORD pgi
, DWORD flags
)
7056 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
7057 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
7060 ERR("called but we don't have FreeType\n");
7064 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7066 ERR("called but we don't have FreeType\n");
7070 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
7071 OUTLINETEXTMETRICW
*potm
)
7073 ERR("called but we don't have FreeType\n");
7077 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
7080 ERR("called but we don't have FreeType\n");
7084 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
7087 ERR("called but we don't have FreeType\n");
7091 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
7093 ERR("called but we don't have FreeType\n");
7097 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
7100 ERR("called but we don't have FreeType\n");
7104 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
7105 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
7107 ERR("called but we don't have FreeType\n");
7111 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
7112 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
7114 ERR("called but we don't have FreeType\n");
7118 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
7121 ERR("called but we don't have FreeType\n");
7125 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
7127 ERR("called but we don't have FreeType\n");
7131 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7133 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7137 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7139 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7143 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7145 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7149 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
7151 FIXME("(%p, %p, %u): stub\n", font
, fs
, flags
);
7152 return DEFAULT_CHARSET
;
7155 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7160 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
7162 FIXME("(%p, %p): stub\n", font
, glyphset
);
7166 BOOL
WineEngFontIsLinked(GdiFont
*font
)
7171 /*************************************************************************
7172 * GetRasterizerCaps (GDI32.@)
7174 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7176 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7178 lprs
->nLanguageID
= 0;
7182 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7184 ERR("called but we don't have FreeType\n");
7188 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
7190 ERR("called but we don't have FreeType\n");
7194 #endif /* HAVE_FREETYPE */