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
{
485 static struct list mappings_list
= LIST_INIT( mappings_list
);
487 static CRITICAL_SECTION freetype_cs
;
488 static CRITICAL_SECTION_DEBUG critsect_debug
=
491 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
492 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
494 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
496 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
498 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
499 static BOOL use_default_fallback
= FALSE
;
501 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
503 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
504 'W','i','n','d','o','w','s',' ','N','T','\\',
505 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
506 'S','y','s','t','e','m','L','i','n','k',0};
508 /****************************************
509 * Notes on .fon files
511 * The fonts System, FixedSys and Terminal are special. There are typically multiple
512 * versions installed for different resolutions and codepages. Windows stores which one to use
513 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
515 * FIXEDFON.FON FixedSys
517 * OEMFONT.FON Terminal
518 * LogPixels Current dpi set by the display control panel applet
519 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
520 * also has a LogPixels value that appears to mirror this)
522 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
523 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
524 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
525 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
526 * so that makes sense.
528 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
529 * to be mapped into the registry on Windows 2000 at least).
532 * ega80woa.fon=ega80850.fon
533 * ega40woa.fon=ega40850.fon
534 * cga80woa.fon=cga80850.fon
535 * cga40woa.fon=cga40850.fon
538 /* These are all structures needed for the GSUB table */
540 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
541 #define TATEGAKI_LOWER_BOUND 0x02F1
557 GSUB_ScriptRecord ScriptRecord
[1];
563 } GSUB_LangSysRecord
;
568 GSUB_LangSysRecord LangSysRecord
[1];
572 WORD LookupOrder
; /* Reserved */
573 WORD ReqFeatureIndex
;
575 WORD FeatureIndex
[1];
581 } GSUB_FeatureRecord
;
585 GSUB_FeatureRecord FeatureRecord
[1];
589 WORD FeatureParams
; /* Reserved */
591 WORD LookupListIndex
[1];
610 } GSUB_CoverageFormat1
;
615 WORD StartCoverageIndex
;
621 GSUB_RangeRecord RangeRecord
[1];
622 } GSUB_CoverageFormat2
;
625 WORD SubstFormat
; /* = 1 */
628 } GSUB_SingleSubstFormat1
;
631 WORD SubstFormat
; /* = 2 */
635 }GSUB_SingleSubstFormat2
;
637 #ifdef HAVE_CARBON_CARBON_H
638 static char *find_cache_dir(void)
642 static char cached_path
[MAX_PATH
];
643 static const char *wine
= "/Wine", *fonts
= "/Fonts";
645 if(*cached_path
) return cached_path
;
647 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
650 WARN("can't create cached data folder\n");
653 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
656 WARN("can't create cached data path\n");
660 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
662 ERR("Could not create full path\n");
666 strcat(cached_path
, wine
);
668 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
670 WARN("Couldn't mkdir %s\n", cached_path
);
674 strcat(cached_path
, fonts
);
675 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
677 WARN("Couldn't mkdir %s\n", cached_path
);
684 /******************************************************************
687 * Extracts individual TrueType font files from a Mac suitcase font
688 * and saves them into the user's caches directory (see
690 * Returns a NULL terminated array of filenames.
692 * We do this because they are apps that try to read ttf files
693 * themselves and they don't like Mac suitcase files.
695 static char **expand_mac_font(const char *path
)
702 const char *filename
;
706 unsigned int size
, max_size
;
709 TRACE("path %s\n", path
);
711 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
714 WARN("failed to get ref\n");
718 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
721 TRACE("no data fork, so trying resource fork\n");
722 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
725 TRACE("unable to open resource fork\n");
732 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
735 CloseResFile(res_ref
);
739 out_dir
= find_cache_dir();
741 filename
= strrchr(path
, '/');
742 if(!filename
) filename
= path
;
745 /* output filename has the form out_dir/filename_%04x.ttf */
746 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
753 unsigned short *num_faces_ptr
, num_faces
, face
;
756 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
758 fond
= Get1IndResource(fond_res
, idx
);
760 TRACE("got fond resource %d\n", idx
);
763 fam_rec
= *(FamRec
**)fond
;
764 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
765 num_faces
= GET_BE_WORD(*num_faces_ptr
);
767 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
768 TRACE("num faces %04x\n", num_faces
);
769 for(face
= 0; face
< num_faces
; face
++, assoc
++)
772 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
773 unsigned short size
, font_id
;
776 size
= GET_BE_WORD(assoc
->fontSize
);
777 font_id
= GET_BE_WORD(assoc
->fontID
);
780 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
784 TRACE("trying to load sfnt id %04x\n", font_id
);
785 sfnt
= GetResource(sfnt_res
, font_id
);
788 TRACE("can't get sfnt resource %04x\n", font_id
);
792 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
797 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
799 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
800 if(fd
!= -1 || errno
== EEXIST
)
804 unsigned char *sfnt_data
;
807 sfnt_data
= *(unsigned char**)sfnt
;
808 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
812 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
815 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
817 ret
.array
[ret
.size
++] = output
;
821 WARN("unable to create %s\n", output
);
822 HeapFree(GetProcessHeap(), 0, output
);
825 ReleaseResource(sfnt
);
828 ReleaseResource(fond
);
831 CloseResFile(res_ref
);
836 #endif /* HAVE_CARBON_CARBON_H */
838 static inline BOOL
is_win9x(void)
840 return GetVersion() & 0x80000000;
843 This function builds an FT_Fixed from a double. It fails if the absolute
844 value of the float number is greater than 32768.
846 static inline FT_Fixed
FT_FixedFromFloat(double f
)
852 This function builds an FT_Fixed from a FIXED. It simply put f.value
853 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
855 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
857 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
861 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
866 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
867 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
869 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
870 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
872 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
874 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
876 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
880 file
= strrchr(face
->file
, '/');
885 if(!strcasecmp(file
, file_nameA
))
887 HeapFree(GetProcessHeap(), 0, file_nameA
);
892 HeapFree(GetProcessHeap(), 0, file_nameA
);
896 static Family
*find_family_from_name(const WCHAR
*name
)
900 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
902 if(!strcmpiW(family
->FamilyName
, name
))
909 static void DumpSubstList(void)
913 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
915 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
916 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
917 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
919 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
920 debugstr_w(psub
->to
.name
));
925 static LPWSTR
strdupW(LPCWSTR p
)
928 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
929 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
934 static LPSTR
strdupA(LPCSTR p
)
937 DWORD len
= (strlen(p
) + 1);
938 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
943 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
948 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
950 if(!strcmpiW(element
->from
.name
, from_name
) &&
951 (element
->from
.charset
== from_charset
||
952 element
->from
.charset
== -1))
959 #define ADD_FONT_SUBST_FORCE 1
961 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
963 FontSubst
*from_exist
, *to_exist
;
965 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
967 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
969 list_remove(&from_exist
->entry
);
970 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
971 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
972 HeapFree(GetProcessHeap(), 0, from_exist
);
978 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
982 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
983 subst
->to
.name
= strdupW(to_exist
->to
.name
);
986 list_add_tail(subst_list
, &subst
->entry
);
991 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
992 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
993 HeapFree(GetProcessHeap(), 0, subst
);
997 static void split_subst_info(NameCs
*nc
, LPSTR str
)
999 CHAR
*p
= strrchr(str
, ',');
1004 nc
->charset
= strtol(p
+1, NULL
, 10);
1007 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
1008 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1009 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
1012 static void LoadSubstList(void)
1016 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1020 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1021 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1022 &hkey
) == ERROR_SUCCESS
) {
1024 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1025 &valuelen
, &datalen
, NULL
, NULL
);
1027 valuelen
++; /* returned value doesn't include room for '\0' */
1028 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1029 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1033 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1034 &dlen
) == ERROR_SUCCESS
) {
1035 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1037 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1038 split_subst_info(&psub
->from
, value
);
1039 split_subst_info(&psub
->to
, data
);
1041 /* Win 2000 doesn't allow mapping between different charsets
1042 or mapping of DEFAULT_CHARSET */
1043 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1044 psub
->to
.charset
== DEFAULT_CHARSET
) {
1045 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1046 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1047 HeapFree(GetProcessHeap(), 0, psub
);
1049 add_font_subst(&font_subst_list
, psub
, 0);
1051 /* reset dlen and vlen */
1055 HeapFree(GetProcessHeap(), 0, data
);
1056 HeapFree(GetProcessHeap(), 0, value
);
1062 /*****************************************************************
1063 * get_name_table_entry
1065 * Supply the platform, encoding, language and name ids in req
1066 * and if the name exists the function will fill in the string
1067 * and string_len members. The string is owned by FreeType so
1068 * don't free it. Returns TRUE if the name is found else FALSE.
1070 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1073 FT_UInt num_names
, name_index
;
1075 if(FT_IS_SFNT(ft_face
))
1077 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1079 for(name_index
= 0; name_index
< num_names
; name_index
++)
1081 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1083 if((name
.platform_id
== req
->platform_id
) &&
1084 (name
.encoding_id
== req
->encoding_id
) &&
1085 (name
.language_id
== req
->language_id
) &&
1086 (name
.name_id
== req
->name_id
))
1088 req
->string
= name
.string
;
1089 req
->string_len
= name
.string_len
;
1096 req
->string_len
= 0;
1100 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1105 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1106 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1107 name
.language_id
= language_id
;
1108 name
.name_id
= name_id
;
1110 if(get_name_table_entry(ft_face
, &name
))
1114 /* String is not nul terminated and string_len is a byte length. */
1115 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1116 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1118 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1119 ret
[i
] = GET_BE_WORD(*tmp
);
1122 TRACE("Got localised name %s\n", debugstr_w(ret
));
1129 /*****************************************************************
1132 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1133 * of FreeType that don't export this function.
1136 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1141 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1142 if(pFT_Load_Sfnt_Table
)
1144 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1146 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1147 else /* Do it the hard way */
1149 TT_Face tt_face
= (TT_Face
) ft_face
;
1150 SFNT_Interface
*sfnt
;
1151 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1154 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1158 /* A field was added in the middle of the structure in 2.1.x */
1159 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1161 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1169 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1170 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1171 "Please upgrade your freetype library.\n");
1174 err
= FT_Err_Unimplemented_Feature
;
1180 static inline int TestStyles(DWORD flags
, DWORD styles
)
1182 return (flags
& styles
) == styles
;
1185 static int StyleOrdering(Face
*face
)
1187 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1189 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1191 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1193 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1196 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1197 debugstr_w(face
->family
->FamilyName
),
1198 debugstr_w(face
->StyleName
),
1204 /* Add a style of face to a font family using an ordering of the list such
1205 that regular fonts come before bold and italic, and single styles come
1206 before compound styles. */
1207 static void AddFaceToFamily(Face
*face
, Family
*family
)
1211 LIST_FOR_EACH( entry
, &family
->faces
)
1213 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1214 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1216 list_add_before( entry
, &face
->entry
);
1219 #define ADDFONT_EXTERNAL_FONT 0x01
1220 #define ADDFONT_FORCE_BITMAP 0x02
1221 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1225 TT_Header
*pHeader
= NULL
;
1226 WCHAR
*english_family
, *localised_family
, *StyleW
;
1230 struct list
*family_elem_ptr
, *face_elem_ptr
;
1232 FT_Long face_index
= 0, num_faces
;
1233 #ifdef HAVE_FREETYPE_FTWINFNT_H
1234 FT_WinFNT_HeaderRec winfnt_header
;
1236 int i
, bitmap_num
, internal_leading
;
1239 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1240 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1242 #ifdef HAVE_CARBON_CARBON_H
1243 if(file
&& !fake_family
)
1245 char **mac_list
= expand_mac_font(file
);
1248 BOOL had_one
= FALSE
;
1250 for(cursor
= mac_list
; *cursor
; cursor
++)
1253 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1254 HeapFree(GetProcessHeap(), 0, *cursor
);
1256 HeapFree(GetProcessHeap(), 0, mac_list
);
1261 #endif /* HAVE_CARBON_CARBON_H */
1264 char *family_name
= fake_family
;
1268 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1269 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1272 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1273 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1277 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1281 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*/
1282 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1283 pFT_Done_Face(ft_face
);
1287 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1288 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1289 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1290 pFT_Done_Face(ft_face
);
1294 if(FT_IS_SFNT(ft_face
))
1296 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1297 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1298 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1300 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1301 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1302 pFT_Done_Face(ft_face
);
1306 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1307 we don't want to load these. */
1308 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1312 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1314 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1315 pFT_Done_Face(ft_face
);
1321 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1322 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1323 pFT_Done_Face(ft_face
);
1327 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1329 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1330 pFT_Done_Face(ft_face
);
1336 localised_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID());
1337 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1339 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1340 HeapFree(GetProcessHeap(), 0, localised_family
);
1341 num_faces
= ft_face
->num_faces
;
1342 pFT_Done_Face(ft_face
);
1345 HeapFree(GetProcessHeap(), 0, localised_family
);
1349 family_name
= ft_face
->family_name
;
1353 My_FT_Bitmap_Size
*size
= NULL
;
1356 if(!FT_IS_SCALABLE(ft_face
))
1357 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1359 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1360 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1361 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1363 localised_family
= NULL
;
1365 localised_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID());
1366 if(localised_family
&& !strcmpiW(localised_family
, english_family
)) {
1367 HeapFree(GetProcessHeap(), 0, localised_family
);
1368 localised_family
= NULL
;
1373 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1374 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1375 if(!strcmpiW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1380 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1381 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1382 family
->EnglishName
= localised_family
? strdupW(english_family
) : NULL
;
1383 list_init(&family
->faces
);
1384 list_add_tail(&font_list
, &family
->entry
);
1386 if(localised_family
) {
1387 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1388 subst
->from
.name
= strdupW(english_family
);
1389 subst
->from
.charset
= -1;
1390 subst
->to
.name
= strdupW(localised_family
);
1391 subst
->to
.charset
= -1;
1392 add_font_subst(&font_subst_list
, subst
, 0);
1395 HeapFree(GetProcessHeap(), 0, localised_family
);
1396 HeapFree(GetProcessHeap(), 0, english_family
);
1398 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1399 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1400 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1402 internal_leading
= 0;
1403 memset(&fs
, 0, sizeof(fs
));
1405 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1407 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1408 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1409 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1410 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1411 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1412 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1413 if(pOS2
->version
== 0) {
1416 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1417 fs
.fsCsb
[0] |= FS_LATIN1
;
1419 fs
.fsCsb
[0] |= FS_SYMBOL
;
1422 #ifdef HAVE_FREETYPE_FTWINFNT_H
1423 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1425 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1426 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1427 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1429 internal_leading
= winfnt_header
.internal_leading
;
1433 face_elem_ptr
= list_head(&family
->faces
);
1434 while(face_elem_ptr
) {
1435 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1436 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1437 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1438 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1439 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1440 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1441 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1444 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1445 HeapFree(GetProcessHeap(), 0, StyleW
);
1446 pFT_Done_Face(ft_face
);
1449 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1450 TRACE("Original font is newer so skipping this one\n");
1451 HeapFree(GetProcessHeap(), 0, StyleW
);
1452 pFT_Done_Face(ft_face
);
1455 TRACE("Replacing original with this one\n");
1456 list_remove(&face
->entry
);
1457 HeapFree(GetProcessHeap(), 0, face
->file
);
1458 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1459 HeapFree(GetProcessHeap(), 0, face
->FullName
);
1460 HeapFree(GetProcessHeap(), 0, face
);
1465 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1466 face
->cached_enum_data
= NULL
;
1467 face
->StyleName
= StyleW
;
1468 face
->FullName
= get_face_name(ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1471 face
->file
= strdupA(file
);
1472 face
->font_data_ptr
= NULL
;
1473 face
->font_data_size
= 0;
1478 face
->font_data_ptr
= font_data_ptr
;
1479 face
->font_data_size
= font_data_size
;
1481 face
->face_index
= face_index
;
1483 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1484 face
->ntmFlags
|= NTM_ITALIC
;
1485 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1486 face
->ntmFlags
|= NTM_BOLD
;
1487 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1488 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1489 face
->family
= family
;
1490 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1492 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1494 if(FT_IS_SCALABLE(ft_face
)) {
1495 memset(&face
->size
, 0, sizeof(face
->size
));
1496 face
->scalable
= TRUE
;
1498 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1499 size
->height
, size
->width
, size
->size
>> 6,
1500 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1501 face
->size
.height
= size
->height
;
1502 face
->size
.width
= size
->width
;
1503 face
->size
.size
= size
->size
;
1504 face
->size
.x_ppem
= size
->x_ppem
;
1505 face
->size
.y_ppem
= size
->y_ppem
;
1506 face
->size
.internal_leading
= internal_leading
;
1507 face
->scalable
= FALSE
;
1510 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1512 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1514 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1515 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1518 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1519 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1520 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1521 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1524 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1525 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1526 switch(ft_face
->charmaps
[i
]->encoding
) {
1527 case FT_ENCODING_UNICODE
:
1528 case FT_ENCODING_APPLE_ROMAN
:
1529 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1531 case FT_ENCODING_MS_SYMBOL
:
1532 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1540 AddFaceToFamily(face
, family
);
1542 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1544 num_faces
= ft_face
->num_faces
;
1545 pFT_Done_Face(ft_face
);
1546 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1547 debugstr_w(StyleW
));
1548 } while(num_faces
> ++face_index
);
1552 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1554 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1557 static void DumpFontList(void)
1561 struct list
*family_elem_ptr
, *face_elem_ptr
;
1563 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1564 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1565 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1566 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1567 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1568 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1570 TRACE(" %d", face
->size
.height
);
1577 /***********************************************************
1578 * The replacement list is a way to map an entire font
1579 * family onto another family. For example adding
1581 * [HKCU\Software\Wine\Fonts\Replacements]
1582 * "Wingdings"="Winedings"
1584 * would enumerate the Winedings font both as Winedings and
1585 * Wingdings. However if a real Wingdings font is present the
1586 * replacement does not take place.
1589 static void LoadReplaceList(void)
1592 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1597 struct list
*family_elem_ptr
, *face_elem_ptr
;
1600 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1601 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1603 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1604 &valuelen
, &datalen
, NULL
, NULL
);
1606 valuelen
++; /* returned value doesn't include room for '\0' */
1607 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1608 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1612 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1613 &dlen
) == ERROR_SUCCESS
) {
1614 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1615 /* "NewName"="Oldname" */
1616 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1618 if(!find_family_from_name(value
))
1620 /* Find the old family and hence all of the font files
1622 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1623 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1624 if(!strcmpiW(family
->FamilyName
, data
)) {
1625 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1626 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1627 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1628 debugstr_w(face
->StyleName
), familyA
);
1629 /* Now add a new entry with the new family name */
1630 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
,
1631 familyA
, family
->FamilyName
,
1632 ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1638 /* reset dlen and vlen */
1642 HeapFree(GetProcessHeap(), 0, data
);
1643 HeapFree(GetProcessHeap(), 0, value
);
1648 /*************************************************************
1651 static BOOL
init_system_links(void)
1655 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1656 WCHAR
*value
, *data
;
1657 WCHAR
*entry
, *next
;
1658 SYSTEM_LINKS
*font_link
, *system_font_link
;
1659 CHILD_FONT
*child_font
;
1660 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1661 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1667 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1669 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1670 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1671 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1672 val_len
= max_val
+ 1;
1673 data_len
= max_data
;
1675 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1677 memset(&fs
, 0, sizeof(fs
));
1678 psub
= get_font_subst(&font_subst_list
, value
, -1);
1679 /* Don't store fonts that are only substitutes for other fonts */
1682 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1685 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1686 font_link
->font_name
= strdupW(value
);
1687 list_init(&font_link
->links
);
1688 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1691 CHILD_FONT
*child_font
;
1693 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1695 next
= entry
+ strlenW(entry
) + 1;
1697 face_name
= strchrW(entry
, ',');
1701 while(isspaceW(*face_name
))
1704 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1706 face_name
= psub
->to
.name
;
1708 face
= find_face_from_filename(entry
, face_name
);
1711 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1715 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1716 child_font
->face
= face
;
1717 child_font
->font
= NULL
;
1718 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1719 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1720 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1721 list_add_tail(&font_link
->links
, &child_font
->entry
);
1723 family
= find_family_from_name(font_link
->font_name
);
1726 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1728 face
->fs_links
= fs
;
1731 list_add_tail(&system_links
, &font_link
->entry
);
1733 val_len
= max_val
+ 1;
1734 data_len
= max_data
;
1737 HeapFree(GetProcessHeap(), 0, value
);
1738 HeapFree(GetProcessHeap(), 0, data
);
1742 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1745 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1746 system_font_link
->font_name
= strdupW(System
);
1747 list_init(&system_font_link
->links
);
1749 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1752 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1753 child_font
->face
= face
;
1754 child_font
->font
= NULL
;
1755 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1756 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1758 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1760 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1762 CHILD_FONT
*font_link_entry
;
1763 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1765 CHILD_FONT
*new_child
;
1766 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1767 new_child
->face
= font_link_entry
->face
;
1768 new_child
->font
= NULL
;
1769 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1774 list_add_tail(&system_links
, &system_font_link
->entry
);
1778 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1781 struct dirent
*dent
;
1782 char path
[MAX_PATH
];
1784 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1786 dir
= opendir(dirname
);
1788 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1791 while((dent
= readdir(dir
)) != NULL
) {
1792 struct stat statbuf
;
1794 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1797 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1799 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1801 if(stat(path
, &statbuf
) == -1)
1803 WARN("Can't stat %s\n", debugstr_a(path
));
1806 if(S_ISDIR(statbuf
.st_mode
))
1807 ReadFontDir(path
, external_fonts
);
1809 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1815 static void load_fontconfig_fonts(void)
1817 #ifdef SONAME_LIBFONTCONFIG
1818 void *fc_handle
= NULL
;
1827 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1829 TRACE("Wine cannot find the fontconfig library (%s).\n",
1830 SONAME_LIBFONTCONFIG
);
1833 #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;}
1834 LOAD_FUNCPTR(FcConfigGetCurrent
);
1835 LOAD_FUNCPTR(FcFontList
);
1836 LOAD_FUNCPTR(FcFontSetDestroy
);
1837 LOAD_FUNCPTR(FcInit
);
1838 LOAD_FUNCPTR(FcObjectSetAdd
);
1839 LOAD_FUNCPTR(FcObjectSetCreate
);
1840 LOAD_FUNCPTR(FcObjectSetDestroy
);
1841 LOAD_FUNCPTR(FcPatternCreate
);
1842 LOAD_FUNCPTR(FcPatternDestroy
);
1843 LOAD_FUNCPTR(FcPatternGetBool
);
1844 LOAD_FUNCPTR(FcPatternGetString
);
1847 if(!pFcInit()) return;
1849 config
= pFcConfigGetCurrent();
1850 pat
= pFcPatternCreate();
1851 os
= pFcObjectSetCreate();
1852 pFcObjectSetAdd(os
, FC_FILE
);
1853 pFcObjectSetAdd(os
, FC_SCALABLE
);
1854 fontset
= pFcFontList(config
, pat
, os
);
1855 if(!fontset
) return;
1856 for(i
= 0; i
< fontset
->nfont
; i
++) {
1859 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1861 TRACE("fontconfig: %s\n", file
);
1863 /* We're just interested in OT/TT fonts for now, so this hack just
1864 picks up the scalable fonts without extensions .pf[ab] to save time
1865 loading every other font */
1867 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1869 TRACE("not scalable\n");
1873 len
= strlen( file
);
1874 if(len
< 4) continue;
1875 ext
= &file
[ len
- 3 ];
1876 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1877 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1879 pFcFontSetDestroy(fontset
);
1880 pFcObjectSetDestroy(os
);
1881 pFcPatternDestroy(pat
);
1887 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1890 const char *data_dir
= wine_get_data_dir();
1892 if (!data_dir
) data_dir
= wine_get_build_dir();
1899 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1901 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1903 strcpy(unix_name
, data_dir
);
1904 strcat(unix_name
, "/fonts/");
1906 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1908 EnterCriticalSection( &freetype_cs
);
1909 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1910 LeaveCriticalSection( &freetype_cs
);
1911 HeapFree(GetProcessHeap(), 0, unix_name
);
1916 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1918 static const WCHAR slashW
[] = {'\\','\0'};
1920 WCHAR windowsdir
[MAX_PATH
];
1923 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1924 strcatW(windowsdir
, fontsW
);
1925 strcatW(windowsdir
, slashW
);
1926 strcatW(windowsdir
, file
);
1927 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1928 EnterCriticalSection( &freetype_cs
);
1929 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1930 LeaveCriticalSection( &freetype_cs
);
1931 HeapFree(GetProcessHeap(), 0, unixname
);
1936 static void load_system_fonts(void)
1939 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1940 const WCHAR
* const *value
;
1942 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1945 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1946 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1947 strcatW(windowsdir
, fontsW
);
1948 for(value
= SystemFontValues
; *value
; value
++) {
1949 dlen
= sizeof(data
);
1950 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1954 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1955 if((unixname
= wine_get_unix_file_name(pathW
))) {
1956 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1957 HeapFree(GetProcessHeap(), 0, unixname
);
1960 load_font_from_data_dir(data
);
1967 /*************************************************************
1969 * This adds registry entries for any externally loaded fonts
1970 * (fonts from fontconfig or FontDirs). It also deletes entries
1971 * of no longer existing fonts.
1974 static void update_reg_entries(void)
1976 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1981 struct list
*family_elem_ptr
, *face_elem_ptr
;
1983 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1984 static const WCHAR spaceW
[] = {' ', '\0'};
1987 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1988 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1989 ERR("Can't create Windows font reg key\n");
1993 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1994 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1995 ERR("Can't create Windows font reg key\n");
1999 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2000 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2001 ERR("Can't create external font reg key\n");
2005 /* enumerate the fonts and add external ones to the two keys */
2007 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2008 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2009 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2010 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2011 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2012 if(!face
->external
) continue;
2014 if (!(face
->ntmFlags
& NTM_REGULAR
))
2015 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2016 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2017 strcpyW(valueW
, family
->FamilyName
);
2018 if(len
!= len_fam
) {
2019 strcatW(valueW
, spaceW
);
2020 strcatW(valueW
, face
->StyleName
);
2022 strcatW(valueW
, TrueType
);
2024 file
= wine_get_dos_file_name(face
->file
);
2026 len
= strlenW(file
) + 1;
2029 if((path
= strrchr(face
->file
, '/')) == NULL
)
2033 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2035 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2036 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2038 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2039 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2040 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2042 HeapFree(GetProcessHeap(), 0, file
);
2043 HeapFree(GetProcessHeap(), 0, valueW
);
2047 if(external_key
) RegCloseKey(external_key
);
2048 if(win9x_key
) RegCloseKey(win9x_key
);
2049 if(winnt_key
) RegCloseKey(winnt_key
);
2053 static void delete_external_font_keys(void)
2055 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2056 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2060 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2061 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2062 ERR("Can't create Windows font reg key\n");
2066 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2067 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2068 ERR("Can't create Windows font reg key\n");
2072 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2073 ERR("Can't create external font reg key\n");
2077 /* Delete all external fonts added last time */
2079 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2080 &valuelen
, &datalen
, NULL
, NULL
);
2081 valuelen
++; /* returned value doesn't include room for '\0' */
2082 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2083 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2085 dlen
= datalen
* sizeof(WCHAR
);
2088 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2089 &dlen
) == ERROR_SUCCESS
) {
2091 RegDeleteValueW(winnt_key
, valueW
);
2092 RegDeleteValueW(win9x_key
, valueW
);
2093 /* reset dlen and vlen */
2097 HeapFree(GetProcessHeap(), 0, data
);
2098 HeapFree(GetProcessHeap(), 0, valueW
);
2100 /* Delete the old external fonts key */
2101 RegCloseKey(external_key
);
2102 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2105 if(win9x_key
) RegCloseKey(win9x_key
);
2106 if(winnt_key
) RegCloseKey(winnt_key
);
2109 /*************************************************************
2110 * WineEngAddFontResourceEx
2113 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2119 if (ft_handle
) /* do it only if we have freetype up and running */
2124 FIXME("Ignoring flags %x\n", flags
);
2126 if((unixname
= wine_get_unix_file_name(file
)))
2128 EnterCriticalSection( &freetype_cs
);
2129 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2130 LeaveCriticalSection( &freetype_cs
);
2131 HeapFree(GetProcessHeap(), 0, unixname
);
2133 if (!ret
&& !strchrW(file
, '\\')) {
2134 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2135 ret
= load_font_from_winfonts_dir(file
);
2137 /* Try in datadir/fonts (or builddir/fonts),
2138 * needed for Magic the Gathering Online
2140 ret
= load_font_from_data_dir(file
);
2147 /*************************************************************
2148 * WineEngAddFontMemResourceEx
2151 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2155 if (ft_handle
) /* do it only if we have freetype up and running */
2157 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2159 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2160 memcpy(pFontCopy
, pbFont
, cbFont
);
2162 EnterCriticalSection( &freetype_cs
);
2163 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2164 LeaveCriticalSection( &freetype_cs
);
2168 TRACE("AddFontToList failed\n");
2169 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2172 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2173 * For now return something unique but quite random
2175 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2176 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2183 /*************************************************************
2184 * WineEngRemoveFontResourceEx
2187 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2190 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2194 static const struct nls_update_font_list
2196 UINT ansi_cp
, oem_cp
;
2197 const char *oem
, *fixed
, *system
;
2198 const char *courier
, *serif
, *small
, *sserif
;
2199 /* these are for font substitutes */
2200 const char *shelldlg
, *tmsrmn
;
2201 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2205 const char *from
, *to
;
2206 } arial_0
, courier_new_0
, times_new_roman_0
;
2207 } nls_update_font_list
[] =
2209 /* Latin 1 (United States) */
2210 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2211 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2212 "Tahoma","Times New Roman",
2213 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2216 /* Latin 1 (Multilingual) */
2217 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2218 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2219 "Tahoma","Times New Roman", /* FIXME unverified */
2220 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2223 /* Eastern Europe */
2224 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2225 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2226 "Tahoma","Times New Roman", /* FIXME unverified */
2227 "Fixedsys,238", "System,238",
2228 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2229 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2230 { "Arial CE,0", "Arial,238" },
2231 { "Courier New CE,0", "Courier New,238" },
2232 { "Times New Roman CE,0", "Times New Roman,238" }
2235 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2236 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2237 "Tahoma","Times New Roman", /* FIXME unverified */
2238 "Fixedsys,204", "System,204",
2239 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2240 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2241 { "Arial Cyr,0", "Arial,204" },
2242 { "Courier New Cyr,0", "Courier New,204" },
2243 { "Times New Roman Cyr,0", "Times New Roman,204" }
2246 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2247 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2248 "Tahoma","Times New Roman", /* FIXME unverified */
2249 "Fixedsys,161", "System,161",
2250 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2251 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2252 { "Arial Greek,0", "Arial,161" },
2253 { "Courier New Greek,0", "Courier New,161" },
2254 { "Times New Roman Greek,0", "Times New Roman,161" }
2257 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2258 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2259 "Tahoma","Times New Roman", /* FIXME unverified */
2260 "Fixedsys,162", "System,162",
2261 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2262 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2263 { "Arial Tur,0", "Arial,162" },
2264 { "Courier New Tur,0", "Courier New,162" },
2265 { "Times New Roman Tur,0", "Times New Roman,162" }
2268 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2269 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2270 "Tahoma","Times New Roman", /* FIXME unverified */
2271 "Fixedsys,177", "System,177",
2272 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2273 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2277 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2278 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2279 "Tahoma","Times New Roman", /* FIXME unverified */
2280 "Fixedsys,178", "System,178",
2281 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2282 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2286 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2287 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2288 "Tahoma","Times New Roman", /* FIXME unverified */
2289 "Fixedsys,186", "System,186",
2290 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2291 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2292 { "Arial Baltic,0", "Arial,186" },
2293 { "Courier New Baltic,0", "Courier New,186" },
2294 { "Times New Roman Baltic,0", "Times New Roman,186" }
2297 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2298 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2299 "Tahoma","Times New Roman", /* FIXME unverified */
2300 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2304 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2306 "Tahoma","Times New Roman", /* FIXME unverified */
2307 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2311 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2312 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2313 "MS UI Gothic","MS Serif",
2314 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2317 /* Chinese Simplified */
2318 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2319 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2320 "SimSun", "NSimSun",
2321 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2325 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2328 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2331 /* Chinese Traditional */
2332 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2333 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2334 "PMingLiU", "MingLiU",
2335 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2340 static const WCHAR
*font_links_list
[] =
2342 Lucida_Sans_Unicode
,
2343 Microsoft_Sans_Serif
,
2347 static const struct font_links_defaults_list
2349 /* Keyed off substitution for "MS Shell Dlg" */
2350 const WCHAR
*shelldlg
;
2351 /* Maximum of four substitutes, plus terminating NULL pointer */
2352 const WCHAR
*substitutes
[5];
2353 } font_links_defaults_list
[] =
2355 /* Non East-Asian */
2356 { Tahoma
, /* FIXME unverified ordering */
2357 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2359 /* Below lists are courtesy of
2360 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2364 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2366 /* Chinese Simplified */
2368 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2372 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2374 /* Chinese Traditional */
2376 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2380 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2382 return ( ansi_cp
== 932 /* CP932 for Japanese */
2383 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2384 || ansi_cp
== 949 /* CP949 for Korean */
2385 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2388 static inline HKEY
create_fonts_NT_registry_key(void)
2392 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2393 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2397 static inline HKEY
create_fonts_9x_registry_key(void)
2401 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2402 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2406 static inline HKEY
create_config_fonts_registry_key(void)
2410 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2411 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2415 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2417 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2418 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2419 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2420 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2423 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2426 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2428 RegDeleteValueA(hkey
, name
);
2431 static void update_font_info(void)
2433 char buf
[40], cpbuf
[40];
2436 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2439 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2442 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2443 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2444 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2445 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2446 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2448 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2449 if (is_dbcs_ansi_cp(ansi_cp
))
2450 use_default_fallback
= TRUE
;
2453 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2455 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2460 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2462 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2464 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2467 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2471 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2472 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2474 hkey
= create_config_fonts_registry_key();
2475 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2476 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2477 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2480 hkey
= create_fonts_NT_registry_key();
2481 add_font_list(hkey
, &nls_update_font_list
[i
]);
2484 hkey
= create_fonts_9x_registry_key();
2485 add_font_list(hkey
, &nls_update_font_list
[i
]);
2488 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2490 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2491 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2492 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2493 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2495 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2496 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2497 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2498 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2499 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2500 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2501 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2502 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2504 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2505 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2506 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2514 /* Delete the FontSubstitutes from other locales */
2515 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2517 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2518 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2519 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2525 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2527 /* Clear out system links */
2528 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, system_link
);
2531 static void populate_system_links(HKEY hkey
, const WCHAR
*name
, const WCHAR
*const *values
)
2541 WCHAR buff
[MAX_PATH
];
2545 static const WCHAR comma
[] = {',',0};
2547 RegDeleteValueW(hkey
, name
);
2552 for (i
= 0; values
[i
] != NULL
; i
++)
2555 if (!strcmpiW(name
,value
))
2557 psub
= get_font_subst(&font_subst_list
, value
, -1);
2559 value
= psub
->to
.name
;
2560 family
= find_family_from_name(value
);
2564 /* Use first extant filename for this Family */
2565 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2569 file
= strrchr(face
->file
, '/');
2578 fileLen
= MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, NULL
, 0);
2579 fileW
= HeapAlloc(GetProcessHeap(), 0, fileLen
* sizeof(WCHAR
));
2580 MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, fileW
, fileLen
);
2581 entryLen
= strlenW(fileW
) + 1 + strlenW(value
) + 1;
2582 if (sizeof(buff
)-(data
-buff
) < entryLen
+ 1)
2584 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name
));
2585 HeapFree(GetProcessHeap(), 0, fileW
);
2588 strcpyW(data
, fileW
);
2589 strcatW(data
, comma
);
2590 strcatW(data
, value
);
2592 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2593 HeapFree(GetProcessHeap(), 0, fileW
);
2599 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (BYTE
*)buff
, (data
-buff
) * sizeof(WCHAR
));
2601 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name
));
2603 TRACE("removed SystemLink for %s\n", debugstr_w(name
));
2606 static void update_system_links(void)
2614 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2616 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE
, system_link
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, &disposition
))
2618 if (disposition
== REG_OPENED_EXISTING_KEY
)
2620 TRACE("SystemLink key already exists, doing nothing\n");
2625 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2627 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2632 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2634 if (!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
))
2636 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2637 populate_system_links(hkey
, font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2639 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2640 populate_system_links(hkey
, psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2643 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2645 populate_system_links(hkey
, font_links_defaults_list
[i
].substitutes
[0], NULL
);
2650 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub
->to
.name
));
2652 WARN("failed to create SystemLink key\n");
2656 static BOOL
init_freetype(void)
2658 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2661 "Wine cannot find the FreeType font library. To enable Wine to\n"
2662 "use TrueType fonts please install a version of FreeType greater than\n"
2663 "or equal to 2.0.5.\n"
2664 "http://www.freetype.org\n");
2668 #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;}
2670 LOAD_FUNCPTR(FT_Vector_Unit
)
2671 LOAD_FUNCPTR(FT_Done_Face
)
2672 LOAD_FUNCPTR(FT_Get_Char_Index
)
2673 LOAD_FUNCPTR(FT_Get_Module
)
2674 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2675 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2676 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2677 LOAD_FUNCPTR(FT_Init_FreeType
)
2678 LOAD_FUNCPTR(FT_Load_Glyph
)
2679 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2680 #ifndef FT_MULFIX_INLINED
2681 LOAD_FUNCPTR(FT_MulFix
)
2683 LOAD_FUNCPTR(FT_New_Face
)
2684 LOAD_FUNCPTR(FT_New_Memory_Face
)
2685 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2686 LOAD_FUNCPTR(FT_Outline_Transform
)
2687 LOAD_FUNCPTR(FT_Outline_Translate
)
2688 LOAD_FUNCPTR(FT_Select_Charmap
)
2689 LOAD_FUNCPTR(FT_Set_Charmap
)
2690 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2691 LOAD_FUNCPTR(FT_Vector_Transform
)
2692 LOAD_FUNCPTR(FT_Render_Glyph
)
2695 /* Don't warn if these ones are missing */
2696 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2697 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2698 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2699 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2700 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2701 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2702 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2704 #ifdef HAVE_FREETYPE_FTWINFNT_H
2705 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2707 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2708 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2709 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2710 <= 2.0.3 has FT_Sqrt64 */
2714 if(pFT_Init_FreeType(&library
) != 0) {
2715 ERR("Can't init FreeType library\n");
2716 wine_dlclose(ft_handle
, NULL
, 0);
2720 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2721 if (pFT_Library_Version
)
2722 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2724 if (FT_Version
.major
<=0)
2730 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2731 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2732 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2733 ((FT_Version
.patch
) & 0x0000ff);
2739 "Wine cannot find certain functions that it needs inside the FreeType\n"
2740 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2741 "FreeType to at least version 2.0.5.\n"
2742 "http://www.freetype.org\n");
2743 wine_dlclose(ft_handle
, NULL
, 0);
2748 static void init_font_list(void)
2750 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2751 static const WCHAR pathW
[] = {'P','a','t','h',0};
2753 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2754 WCHAR windowsdir
[MAX_PATH
];
2756 const char *data_dir
;
2758 delete_external_font_keys();
2760 /* load the system bitmap fonts */
2761 load_system_fonts();
2763 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2764 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2765 strcatW(windowsdir
, fontsW
);
2766 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2768 ReadFontDir(unixname
, FALSE
);
2769 HeapFree(GetProcessHeap(), 0, unixname
);
2772 /* load the system truetype fonts */
2773 data_dir
= wine_get_data_dir();
2774 if (!data_dir
) data_dir
= wine_get_build_dir();
2775 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
2777 strcpy(unixname
, data_dir
);
2778 strcat(unixname
, "/fonts/");
2779 ReadFontDir(unixname
, TRUE
);
2780 HeapFree(GetProcessHeap(), 0, unixname
);
2783 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2784 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2785 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2787 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2788 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2789 &hkey
) == ERROR_SUCCESS
)
2791 LPWSTR data
, valueW
;
2792 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2793 &valuelen
, &datalen
, NULL
, NULL
);
2795 valuelen
++; /* returned value doesn't include room for '\0' */
2796 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2797 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2800 dlen
= datalen
* sizeof(WCHAR
);
2802 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
2803 &dlen
) == ERROR_SUCCESS
)
2805 if(data
[0] && (data
[1] == ':'))
2807 if((unixname
= wine_get_unix_file_name(data
)))
2809 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2810 HeapFree(GetProcessHeap(), 0, unixname
);
2813 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
2815 WCHAR pathW
[MAX_PATH
];
2816 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2819 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2820 if((unixname
= wine_get_unix_file_name(pathW
)))
2822 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2823 HeapFree(GetProcessHeap(), 0, unixname
);
2826 load_font_from_data_dir(data
);
2828 /* reset dlen and vlen */
2833 HeapFree(GetProcessHeap(), 0, data
);
2834 HeapFree(GetProcessHeap(), 0, valueW
);
2838 load_fontconfig_fonts();
2840 /* then look in any directories that we've specified in the config file */
2841 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2842 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2848 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2850 len
+= sizeof(WCHAR
);
2851 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2852 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2854 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2855 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2856 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2857 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2861 LPSTR next
= strchr( ptr
, ':' );
2862 if (next
) *next
++ = 0;
2863 ReadFontDir( ptr
, TRUE
);
2866 HeapFree( GetProcessHeap(), 0, valueA
);
2868 HeapFree( GetProcessHeap(), 0, valueW
);
2874 /*************************************************************
2877 * Initialize FreeType library and create a list of available faces
2879 BOOL
WineEngInit(void)
2883 /* update locale dependent font info in registry */
2886 if(!init_freetype()) return FALSE
;
2888 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
2890 ERR("Failed to create font mutex\n");
2893 WaitForSingleObject(font_mutex
, INFINITE
);
2901 update_reg_entries();
2903 update_system_links();
2904 init_system_links();
2906 ReleaseMutex(font_mutex
);
2911 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2914 TT_HoriHeader
*pHori
;
2918 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2919 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2921 if(height
== 0) height
= 16;
2923 /* Calc. height of EM square:
2925 * For +ve lfHeight we have
2926 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2927 * Re-arranging gives:
2928 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2930 * For -ve lfHeight we have
2932 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2933 * with il = winAscent + winDescent - units_per_em]
2938 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2939 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2940 pHori
->Ascender
- pHori
->Descender
);
2942 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2943 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2951 static struct font_mapping
*map_font_file( const char *name
)
2953 struct font_mapping
*mapping
;
2957 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2958 if (fstat( fd
, &st
) == -1) goto error
;
2960 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2962 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2964 mapping
->refcount
++;
2969 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2972 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2975 if (mapping
->data
== MAP_FAILED
)
2977 HeapFree( GetProcessHeap(), 0, mapping
);
2980 mapping
->refcount
= 1;
2981 mapping
->dev
= st
.st_dev
;
2982 mapping
->ino
= st
.st_ino
;
2983 mapping
->size
= st
.st_size
;
2984 list_add_tail( &mappings_list
, &mapping
->entry
);
2992 static void unmap_font_file( struct font_mapping
*mapping
)
2994 if (!--mapping
->refcount
)
2996 list_remove( &mapping
->entry
);
2997 munmap( mapping
->data
, mapping
->size
);
2998 HeapFree( GetProcessHeap(), 0, mapping
);
3002 static LONG
load_VDMX(GdiFont
*, LONG
);
3004 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3011 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3015 if (!(font
->mapping
= map_font_file( face
->file
)))
3017 WARN("failed to map %s\n", debugstr_a(face
->file
));
3020 data_ptr
= font
->mapping
->data
;
3021 data_size
= font
->mapping
->size
;
3025 data_ptr
= face
->font_data_ptr
;
3026 data_size
= face
->font_data_size
;
3029 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3031 ERR("FT_New_Face rets %d\n", err
);
3035 /* set it here, as load_VDMX needs it */
3036 font
->ft_face
= ft_face
;
3038 if(FT_IS_SCALABLE(ft_face
)) {
3039 /* load the VDMX table if we have one */
3040 font
->ppem
= load_VDMX(font
, height
);
3042 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3043 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3045 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3046 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3048 font
->ppem
= height
;
3049 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3050 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3056 static int get_nearest_charset(Face
*face
, int *cp
)
3058 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3059 a single face with the requested charset. The idea is to check if
3060 the selected font supports the current ANSI codepage, if it does
3061 return the corresponding charset, else return the first charset */
3064 int acp
= GetACP(), i
;
3068 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3069 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3070 return csi
.ciCharset
;
3072 for(i
= 0; i
< 32; i
++) {
3074 if(face
->fs
.fsCsb
[0] & fs0
) {
3075 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3077 return csi
.ciCharset
;
3080 FIXME("TCI failing on %x\n", fs0
);
3084 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3085 face
->fs
.fsCsb
[0], face
->file
);
3087 return DEFAULT_CHARSET
;
3090 static GdiFont
*alloc_font(void)
3092 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3094 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3095 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3097 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3098 ret
->total_kern_pairs
= (DWORD
)-1;
3099 ret
->kern_pairs
= NULL
;
3100 list_init(&ret
->hfontlist
);
3101 list_init(&ret
->child_fonts
);
3105 static void free_font(GdiFont
*font
)
3107 struct list
*cursor
, *cursor2
;
3110 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3112 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3113 list_remove(cursor
);
3115 free_font(child
->font
);
3116 HeapFree(GetProcessHeap(), 0, child
);
3119 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3121 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3122 DeleteObject(hfontlist
->hfont
);
3123 list_remove(&hfontlist
->entry
);
3124 HeapFree(GetProcessHeap(), 0, hfontlist
);
3127 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3128 if (font
->mapping
) unmap_font_file( font
->mapping
);
3129 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3130 HeapFree(GetProcessHeap(), 0, font
->potm
);
3131 HeapFree(GetProcessHeap(), 0, font
->name
);
3132 for (i
= 0; i
< font
->gmsize
; i
++)
3133 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3134 HeapFree(GetProcessHeap(), 0, font
->gm
);
3135 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3136 HeapFree(GetProcessHeap(), 0, font
);
3140 /*************************************************************
3143 * load the vdmx entry for the specified height
3146 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3147 ( ( (FT_ULong)_x4 << 24 ) | \
3148 ( (FT_ULong)_x3 << 16 ) | \
3149 ( (FT_ULong)_x2 << 8 ) | \
3152 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3167 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3171 BYTE devXRatio
, devYRatio
;
3172 USHORT numRecs
, numRatios
;
3173 DWORD result
, offset
= -1;
3177 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3179 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3182 /* FIXME: need the real device aspect ratio */
3186 numRecs
= GET_BE_WORD(hdr
[1]);
3187 numRatios
= GET_BE_WORD(hdr
[2]);
3189 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3190 for(i
= 0; i
< numRatios
; i
++) {
3193 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3194 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3197 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3199 if((ratio
.xRatio
== 0 &&
3200 ratio
.yStartRatio
== 0 &&
3201 ratio
.yEndRatio
== 0) ||
3202 (devXRatio
== ratio
.xRatio
&&
3203 devYRatio
>= ratio
.yStartRatio
&&
3204 devYRatio
<= ratio
.yEndRatio
))
3206 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3207 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3208 offset
= GET_BE_WORD(tmp
);
3214 FIXME("No suitable ratio found\n");
3218 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3220 BYTE startsz
, endsz
;
3223 recs
= GET_BE_WORD(group
.recs
);
3224 startsz
= group
.startsz
;
3225 endsz
= group
.endsz
;
3227 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3229 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3230 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3231 if(result
== GDI_ERROR
) {
3232 FIXME("Failed to retrieve vTable\n");
3237 for(i
= 0; i
< recs
; i
++) {
3238 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3239 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3240 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3242 if(yMax
+ -yMin
== height
) {
3245 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3248 if(yMax
+ -yMin
> height
) {
3251 goto end
; /* failed */
3253 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3254 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3255 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3256 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3262 TRACE("ppem not found for height %d\n", height
);
3266 HeapFree(GetProcessHeap(), 0, vTable
);
3272 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3274 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3275 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3276 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3277 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3278 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3281 static void calc_hash(FONT_DESC
*pfd
)
3283 DWORD hash
= 0, *ptr
, two_chars
;
3287 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3289 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3291 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3293 pwc
= (WCHAR
*)&two_chars
;
3295 *pwc
= toupperW(*pwc
);
3297 *pwc
= toupperW(*pwc
);
3301 hash
^= !pfd
->can_use_bitmap
;
3306 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3311 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3315 fd
.can_use_bitmap
= can_use_bitmap
;
3318 /* try the child list */
3319 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3320 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3321 if(!fontcmp(ret
, &fd
)) {
3322 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3323 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3324 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3325 if(hflist
->hfont
== hfont
)
3331 /* try the in-use list */
3332 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3333 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3334 if(!fontcmp(ret
, &fd
)) {
3335 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3336 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3337 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3338 if(hflist
->hfont
== hfont
)
3341 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3342 hflist
->hfont
= hfont
;
3343 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3348 /* then the unused list */
3349 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3350 while(font_elem_ptr
) {
3351 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3352 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3353 if(!fontcmp(ret
, &fd
)) {
3354 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3355 assert(list_empty(&ret
->hfontlist
));
3356 TRACE("Found %p in unused list\n", ret
);
3357 list_remove(&ret
->entry
);
3358 list_add_head(&gdi_font_list
, &ret
->entry
);
3359 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3360 hflist
->hfont
= hfont
;
3361 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3368 static void add_to_cache(GdiFont
*font
)
3370 static DWORD cache_num
= 1;
3372 font
->cache_num
= cache_num
++;
3373 list_add_head(&gdi_font_list
, &font
->entry
);
3376 /*************************************************************
3377 * create_child_font_list
3379 static BOOL
create_child_font_list(GdiFont
*font
)
3382 SYSTEM_LINKS
*font_link
;
3383 CHILD_FONT
*font_link_entry
, *new_child
;
3387 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3388 font_name
= psub
? psub
->to
.name
: font
->name
;
3389 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3391 if(!strcmpiW(font_link
->font_name
, font_name
))
3393 TRACE("found entry in system list\n");
3394 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3396 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3397 new_child
->face
= font_link_entry
->face
;
3398 new_child
->font
= NULL
;
3399 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3400 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3407 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3408 * Sans Serif. This is how asian windows get default fallbacks for fonts
3410 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3411 font
->charset
!= OEM_CHARSET
&&
3412 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3413 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3415 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3417 TRACE("found entry in default fallback list\n");
3418 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3420 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3421 new_child
->face
= font_link_entry
->face
;
3422 new_child
->font
= NULL
;
3423 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3424 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3434 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3436 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3438 if (pFT_Set_Charmap
)
3441 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3443 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3445 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3447 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3449 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3450 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3452 switch (ft_face
->charmaps
[i
]->platform_id
)
3455 cmap_def
= ft_face
->charmaps
[i
];
3457 case 0: /* Apple Unicode */
3458 cmap0
= ft_face
->charmaps
[i
];
3460 case 1: /* Macintosh */
3461 cmap1
= ft_face
->charmaps
[i
];
3464 cmap2
= ft_face
->charmaps
[i
];
3466 case 3: /* Microsoft */
3467 cmap3
= ft_face
->charmaps
[i
];
3472 if (cmap3
) /* prefer Microsoft cmap table */
3473 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3475 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3477 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3479 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3481 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3483 return ft_err
== FT_Err_Ok
;
3486 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3489 /*************************************************************
3490 * WineEngCreateFontInstance
3493 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3496 Face
*face
, *best
, *best_bitmap
;
3497 Family
*family
, *last_resort_family
;
3498 struct list
*family_elem_ptr
, *face_elem_ptr
;
3499 INT height
, width
= 0;
3500 unsigned int score
= 0, new_score
;
3501 signed int diff
= 0, newdiff
;
3502 BOOL bd
, it
, can_use_bitmap
;
3507 FontSubst
*psub
= NULL
;
3509 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3510 lf
.lfWidth
= abs(lf
.lfWidth
);
3512 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3514 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3515 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3516 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3519 if(dc
->GraphicsMode
== GM_ADVANCED
)
3520 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3523 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3524 font scaling abilities. */
3525 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3526 dcmat
.eM21
= dcmat
.eM12
= 0;
3529 /* Try to avoid not necessary glyph transformations */
3530 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3532 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3533 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3534 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3537 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3538 dcmat
.eM21
, dcmat
.eM22
);
3541 EnterCriticalSection( &freetype_cs
);
3543 /* check the cache first */
3544 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3545 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3546 LeaveCriticalSection( &freetype_cs
);
3550 TRACE("not in cache\n");
3551 if(list_empty(&font_list
)) /* No fonts installed */
3553 TRACE("No fonts installed\n");
3554 LeaveCriticalSection( &freetype_cs
);
3560 ret
->font_desc
.matrix
= dcmat
;
3561 ret
->font_desc
.lf
= lf
;
3562 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3563 calc_hash(&ret
->font_desc
);
3564 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3565 hflist
->hfont
= hfont
;
3566 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3568 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3569 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3570 original value lfCharSet. Note this is a special case for
3571 Symbol and doesn't happen at least for "Wingdings*" */
3573 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3574 lf
.lfCharSet
= SYMBOL_CHARSET
;
3576 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3577 switch(lf
.lfCharSet
) {
3578 case DEFAULT_CHARSET
:
3579 csi
.fs
.fsCsb
[0] = 0;
3582 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3583 csi
.fs
.fsCsb
[0] = 0;
3589 if(lf
.lfFaceName
[0] != '\0') {
3590 SYSTEM_LINKS
*font_link
;
3591 CHILD_FONT
*font_link_entry
;
3592 LPWSTR FaceName
= lf
.lfFaceName
;
3595 * Check for a leading '@' this signals that the font is being
3596 * requested in tategaki mode (vertical writing substitution) but
3597 * does not affect the fontface that is to be selected.
3599 if (lf
.lfFaceName
[0]=='@')
3600 FaceName
= &lf
.lfFaceName
[1];
3602 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3605 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3606 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3607 if (psub
->to
.charset
!= -1)
3608 lf
.lfCharSet
= psub
->to
.charset
;
3611 /* We want a match on name and charset or just name if
3612 charset was DEFAULT_CHARSET. If the latter then
3613 we fixup the returned charset later in get_nearest_charset
3614 where we'll either use the charset of the current ansi codepage
3615 or if that's unavailable the first charset that the font supports.
3617 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3618 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3619 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3620 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3622 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3623 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3624 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3625 if(face
->scalable
|| can_use_bitmap
)
3631 /* Search by full face name. */
3632 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3633 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3634 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3635 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3636 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
3637 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]))
3639 if(face
->scalable
|| can_use_bitmap
)
3646 * Try check the SystemLink list first for a replacement font.
3647 * We may find good replacements there.
3649 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3651 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3652 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3654 TRACE("found entry in system list\n");
3655 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3657 face
= font_link_entry
->face
;
3658 family
= face
->family
;
3659 if(csi
.fs
.fsCsb
[0] &
3660 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3662 if(face
->scalable
|| can_use_bitmap
)
3670 psub
= NULL
; /* substitution is no more relevant */
3672 /* If requested charset was DEFAULT_CHARSET then try using charset
3673 corresponding to the current ansi codepage */
3674 if (!csi
.fs
.fsCsb
[0])
3677 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3678 FIXME("TCI failed on codepage %d\n", acp
);
3679 csi
.fs
.fsCsb
[0] = 0;
3681 lf
.lfCharSet
= csi
.ciCharset
;
3684 /* Face families are in the top 4 bits of lfPitchAndFamily,
3685 so mask with 0xF0 before testing */
3687 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3688 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3689 strcpyW(lf
.lfFaceName
, defFixed
);
3690 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3691 strcpyW(lf
.lfFaceName
, defSerif
);
3692 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3693 strcpyW(lf
.lfFaceName
, defSans
);
3695 strcpyW(lf
.lfFaceName
, defSans
);
3696 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3697 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3698 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3699 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3700 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3701 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3702 if(face
->scalable
|| can_use_bitmap
)
3708 last_resort_family
= NULL
;
3709 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3710 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3711 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3712 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3713 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3716 if(can_use_bitmap
&& !last_resort_family
)
3717 last_resort_family
= family
;
3722 if(last_resort_family
) {
3723 family
= last_resort_family
;
3724 csi
.fs
.fsCsb
[0] = 0;
3728 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3729 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3730 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3731 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3732 if(face
->scalable
) {
3733 csi
.fs
.fsCsb
[0] = 0;
3734 WARN("just using first face for now\n");
3737 if(can_use_bitmap
&& !last_resort_family
)
3738 last_resort_family
= family
;
3741 if(!last_resort_family
) {
3742 FIXME("can't find a single appropriate font - bailing\n");
3744 LeaveCriticalSection( &freetype_cs
);
3748 WARN("could only find a bitmap font - this will probably look awful!\n");
3749 family
= last_resort_family
;
3750 csi
.fs
.fsCsb
[0] = 0;
3753 it
= lf
.lfItalic
? 1 : 0;
3754 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3756 height
= lf
.lfHeight
;
3758 face
= best
= best_bitmap
= NULL
;
3759 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3761 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3765 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3766 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3767 new_score
= (italic
^ it
) + (bold
^ bd
);
3768 if(!best
|| new_score
<= score
)
3770 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3771 italic
, bold
, it
, bd
);
3774 if(best
->scalable
&& score
== 0) break;
3778 newdiff
= height
- (signed int)(best
->size
.height
);
3780 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3781 if(!best_bitmap
|| new_score
< score
||
3782 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3784 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3787 if(score
== 0 && diff
== 0) break;
3794 face
= best
->scalable
? best
: best_bitmap
;
3795 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3796 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3799 height
= lf
.lfHeight
;
3803 if(csi
.fs
.fsCsb
[0]) {
3804 ret
->charset
= lf
.lfCharSet
;
3805 ret
->codepage
= csi
.ciACP
;
3808 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3810 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3811 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3813 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3815 if(!face
->scalable
) {
3816 /* Windows uses integer scaling factors for bitmap fonts */
3817 INT scale
, scaled_height
;
3818 GdiFont
*cachedfont
;
3820 /* FIXME: rotation of bitmap fonts is ignored */
3821 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3823 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3824 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3825 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3826 /* As we changed the matrix, we need to search the cache for the font again,
3827 * otherwise we might explode the cache. */
3828 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3829 TRACE("Found cached font after non-scalable matrix rescale!\n");
3831 LeaveCriticalSection( &freetype_cs
);
3834 calc_hash(&ret
->font_desc
);
3836 if (height
!= 0) height
= diff
;
3837 height
+= face
->size
.height
;
3839 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3840 scaled_height
= scale
* face
->size
.height
;
3841 /* Only jump to the next height if the difference <= 25% original height */
3842 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3843 /* The jump between unscaled and doubled is delayed by 1 */
3844 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3845 ret
->scale_y
= scale
;
3847 width
= face
->size
.x_ppem
>> 6;
3848 height
= face
->size
.y_ppem
>> 6;
3852 TRACE("font scale y: %f\n", ret
->scale_y
);
3854 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3859 LeaveCriticalSection( &freetype_cs
);
3863 ret
->ntmFlags
= face
->ntmFlags
;
3865 if (ret
->charset
== SYMBOL_CHARSET
&&
3866 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3869 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3873 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3876 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3877 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3878 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3879 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3880 create_child_font_list(ret
);
3882 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3884 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3885 if (length
!= GDI_ERROR
)
3887 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3888 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3889 TRACE("Loaded GSUB table of %i bytes\n",length
);
3893 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3896 LeaveCriticalSection( &freetype_cs
);
3900 static void dump_gdi_font_list(void)
3903 struct list
*elem_ptr
;
3905 TRACE("---------- gdiFont Cache ----------\n");
3906 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3907 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3908 TRACE("gdiFont=%p %s %d\n",
3909 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3912 TRACE("---------- Unused gdiFont Cache ----------\n");
3913 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3914 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3915 TRACE("gdiFont=%p %s %d\n",
3916 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3919 TRACE("---------- Child gdiFont Cache ----------\n");
3920 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
3921 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3922 TRACE("gdiFont=%p %s %d\n",
3923 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3927 /*************************************************************
3928 * WineEngDestroyFontInstance
3930 * free the gdiFont associated with this handle
3933 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3938 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3942 EnterCriticalSection( &freetype_cs
);
3944 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3946 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3947 while(hfontlist_elem_ptr
) {
3948 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3949 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3950 if(hflist
->hfont
== handle
) {
3951 TRACE("removing child font %p from child list\n", gdiFont
);
3952 list_remove(&gdiFont
->entry
);
3953 LeaveCriticalSection( &freetype_cs
);
3959 TRACE("destroying hfont=%p\n", handle
);
3961 dump_gdi_font_list();
3963 font_elem_ptr
= list_head(&gdi_font_list
);
3964 while(font_elem_ptr
) {
3965 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3966 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3968 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3969 while(hfontlist_elem_ptr
) {
3970 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3971 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3972 if(hflist
->hfont
== handle
) {
3973 list_remove(&hflist
->entry
);
3974 HeapFree(GetProcessHeap(), 0, hflist
);
3978 if(list_empty(&gdiFont
->hfontlist
)) {
3979 TRACE("Moving to Unused list\n");
3980 list_remove(&gdiFont
->entry
);
3981 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3986 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3987 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3988 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3989 while(font_elem_ptr
) {
3990 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3991 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3992 TRACE("freeing %p\n", gdiFont
);
3993 list_remove(&gdiFont
->entry
);
3996 LeaveCriticalSection( &freetype_cs
);
4000 /***************************************************
4001 * create_enum_charset_list
4003 * This function creates charset enumeration list because in DEFAULT_CHARSET
4004 * case, the ANSI codepage's charset takes precedence over other charsets.
4005 * This function works as a filter other than DEFAULT_CHARSET case.
4007 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4012 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4013 csi
.fs
.fsCsb
[0] != 0) {
4014 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4015 list
->element
[n
].charset
= csi
.ciCharset
;
4016 list
->element
[n
].name
= ElfScriptsW
[ffs(csi
.fs
.fsCsb
[0]) - 1];
4019 else { /* charset is DEFAULT_CHARSET or invalid. */
4022 /* Set the current codepage's charset as the first element. */
4024 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4025 csi
.fs
.fsCsb
[0] != 0) {
4026 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4027 list
->element
[n
].charset
= csi
.ciCharset
;
4028 list
->element
[n
].name
= ElfScriptsW
[ffs(csi
.fs
.fsCsb
[0]) - 1];
4032 /* Fill out left elements. */
4033 for (i
= 0; i
< 32; i
++) {
4035 fs
.fsCsb
[0] = 1L << i
;
4037 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4038 continue; /* skip, already added. */
4039 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4040 continue; /* skip, this is an invalid fsCsb bit. */
4042 list
->element
[n
].mask
= fs
.fsCsb
[0];
4043 list
->element
[n
].charset
= csi
.ciCharset
;
4044 list
->element
[n
].name
= ElfScriptsW
[i
];
4053 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4054 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4059 if (face
->cached_enum_data
)
4062 *pelf
= face
->cached_enum_data
->elf
;
4063 *pntm
= face
->cached_enum_data
->ntm
;
4064 *ptype
= face
->cached_enum_data
->type
;
4068 font
= alloc_font();
4070 if(face
->scalable
) {
4071 height
= -2048; /* 2048 is the most common em size */
4074 height
= face
->size
.y_ppem
>> 6;
4075 width
= face
->size
.x_ppem
>> 6;
4077 font
->scale_y
= 1.0;
4079 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4085 font
->name
= strdupW(face
->family
->FamilyName
);
4086 font
->ntmFlags
= face
->ntmFlags
;
4088 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4090 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4092 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4094 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4095 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4097 lstrcpynW(pelf
->elfFullName
,
4098 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4100 lstrcpynW(pelf
->elfStyle
,
4101 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4106 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4108 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4110 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4112 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4114 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4115 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4118 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4119 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4120 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4121 pntm
->ntmFontSig
= face
->fs
;
4123 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4125 pelf
->elfLogFont
.lfEscapement
= 0;
4126 pelf
->elfLogFont
.lfOrientation
= 0;
4127 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4128 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4129 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4130 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4131 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4132 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4133 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4134 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4135 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4136 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4137 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4140 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4141 *ptype
|= TRUETYPE_FONTTYPE
;
4142 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4143 *ptype
|= DEVICE_FONTTYPE
;
4144 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4145 *ptype
|= RASTER_FONTTYPE
;
4147 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4148 if (face
->cached_enum_data
)
4150 face
->cached_enum_data
->elf
= *pelf
;
4151 face
->cached_enum_data
->ntm
= *pntm
;
4152 face
->cached_enum_data
->type
= *ptype
;
4158 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4160 struct list
*face_elem_ptr
;
4162 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4164 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
)
4166 static const WCHAR spaceW
[] = { ' ',0 };
4167 WCHAR full_family_name
[LF_FULLFACESIZE
];
4168 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4170 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4172 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4173 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4177 strcpyW(full_family_name
, family
->FamilyName
);
4178 strcatW(full_family_name
, spaceW
);
4179 strcatW(full_family_name
, face
->StyleName
);
4180 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4186 static BOOL
face_matches(Face
*face
, const LOGFONTW
*lf
)
4188 static const WCHAR spaceW
[] = { ' ',0 };
4189 WCHAR full_family_name
[LF_FULLFACESIZE
];
4191 if (!strcmpiW(lf
->lfFaceName
, face
->family
->FamilyName
)) return TRUE
;
4193 if (strlenW(face
->family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4195 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4196 debugstr_w(face
->family
->FamilyName
), debugstr_w(face
->StyleName
));
4200 strcpyW(full_family_name
, face
->family
->FamilyName
);
4201 strcatW(full_family_name
, spaceW
);
4202 strcatW(full_family_name
, face
->StyleName
);
4203 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4206 static BOOL
enum_face_charsets(Face
*face
, struct enum_charset_list
*list
,
4207 FONTENUMPROCW proc
, LPARAM lparam
)
4210 NEWTEXTMETRICEXW ntm
;
4214 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4215 for(i
= 0; i
< list
->total
; i
++) {
4216 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4217 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4218 strcpyW(elf
.elfScript
, OEM_DOSW
);
4219 i
= 32; /* break out of loop */
4220 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4223 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4224 if(list
->element
[i
].name
)
4225 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4227 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4229 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4230 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4231 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4232 list
->element
[i
].charset
, type
, debugstr_w(elf
.elfScript
),
4233 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4234 ntm
.ntmTm
.ntmFlags
);
4235 /* release section before callback (FIXME) */
4236 LeaveCriticalSection( &freetype_cs
);
4237 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4238 EnterCriticalSection( &freetype_cs
);
4243 /*************************************************************
4247 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4251 struct list
*family_elem_ptr
, *face_elem_ptr
;
4253 struct enum_charset_list enum_charsets
;
4257 lf
.lfCharSet
= DEFAULT_CHARSET
;
4258 lf
.lfPitchAndFamily
= 0;
4259 lf
.lfFaceName
[0] = 0;
4263 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4265 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4268 EnterCriticalSection( &freetype_cs
);
4269 if(plf
->lfFaceName
[0]) {
4271 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4274 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4275 debugstr_w(psub
->to
.name
));
4277 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4281 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4282 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4283 if(family_matches(family
, plf
)) {
4284 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4285 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4286 if (!face_matches(face
, plf
)) continue;
4287 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return 0;
4292 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4293 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4294 face_elem_ptr
= list_head(&family
->faces
);
4295 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4296 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return 0;
4299 LeaveCriticalSection( &freetype_cs
);
4303 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4305 pt
->x
.value
= vec
->x
>> 6;
4306 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4307 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4308 pt
->y
.value
= vec
->y
>> 6;
4309 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4310 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4314 /***************************************************
4315 * According to the MSDN documentation on WideCharToMultiByte,
4316 * certain codepages cannot set the default_used parameter.
4317 * This returns TRUE if the codepage can set that parameter, false else
4318 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4320 static BOOL
codepage_sets_default_used(UINT codepage
)
4334 * GSUB Table handling functions
4337 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4339 const GSUB_CoverageFormat1
* cf1
;
4343 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4345 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4347 TRACE("Coverage Format 1, %i glyphs\n",count
);
4348 for (i
= 0; i
< count
; i
++)
4349 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4353 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4355 const GSUB_CoverageFormat2
* cf2
;
4358 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4360 count
= GET_BE_WORD(cf2
->RangeCount
);
4361 TRACE("Coverage Format 2, %i ranges\n",count
);
4362 for (i
= 0; i
< count
; i
++)
4364 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4366 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4367 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4369 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4370 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4376 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4381 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4383 const GSUB_ScriptList
*script
;
4384 const GSUB_Script
*deflt
= NULL
;
4386 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4388 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4389 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4391 const GSUB_Script
*scr
;
4394 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4395 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4397 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4399 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4405 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4409 const GSUB_LangSys
*Lang
;
4411 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4413 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4415 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4416 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4418 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4421 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4424 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4430 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4433 const GSUB_FeatureList
*feature
;
4434 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4436 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4437 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4439 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4440 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4442 const GSUB_Feature
*feat
;
4443 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4450 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4454 const GSUB_LookupList
*lookup
;
4455 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4457 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4458 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4460 const GSUB_LookupTable
*look
;
4461 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4462 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4463 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4464 if (GET_BE_WORD(look
->LookupType
) != 1)
4465 FIXME("We only handle SubType 1\n");
4470 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4472 const GSUB_SingleSubstFormat1
*ssf1
;
4473 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4474 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4475 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4477 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4478 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4479 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4481 TRACE(" Glyph 0x%x ->",glyph
);
4482 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4483 TRACE(" 0x%x\n",glyph
);
4488 const GSUB_SingleSubstFormat2
*ssf2
;
4492 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4493 offset
= GET_BE_WORD(ssf1
->Coverage
);
4494 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4495 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4496 TRACE(" Coverage index %i\n",index
);
4499 TRACE(" Glyph is 0x%x ->",glyph
);
4500 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4501 TRACE("0x%x\n",glyph
);
4510 static const char* get_opentype_script(const GdiFont
*font
)
4513 * I am not sure if this is the correct way to generate our script tag
4516 switch (font
->charset
)
4518 case ANSI_CHARSET
: return "latn";
4519 case BALTIC_CHARSET
: return "latn"; /* ?? */
4520 case CHINESEBIG5_CHARSET
: return "hani";
4521 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4522 case GB2312_CHARSET
: return "hani";
4523 case GREEK_CHARSET
: return "grek";
4524 case HANGUL_CHARSET
: return "hang";
4525 case RUSSIAN_CHARSET
: return "cyrl";
4526 case SHIFTJIS_CHARSET
: return "kana";
4527 case TURKISH_CHARSET
: return "latn"; /* ?? */
4528 case VIETNAMESE_CHARSET
: return "latn";
4529 case JOHAB_CHARSET
: return "latn"; /* ?? */
4530 case ARABIC_CHARSET
: return "arab";
4531 case HEBREW_CHARSET
: return "hebr";
4532 case THAI_CHARSET
: return "thai";
4533 default: return "latn";
4537 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4539 const GSUB_Header
*header
;
4540 const GSUB_Script
*script
;
4541 const GSUB_LangSys
*language
;
4542 const GSUB_Feature
*feature
;
4544 if (!font
->GSUB_Table
)
4547 header
= font
->GSUB_Table
;
4549 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4552 TRACE("Script not found\n");
4555 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4558 TRACE("Language not found\n");
4561 feature
= GSUB_get_feature(header
, language
, "vrt2");
4563 feature
= GSUB_get_feature(header
, language
, "vert");
4566 TRACE("vrt2/vert feature not found\n");
4569 return GSUB_apply_feature(header
, feature
, glyph
);
4572 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4576 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4577 WCHAR wc
= (WCHAR
)glyph
;
4579 BOOL
*default_used_pointer
;
4582 default_used_pointer
= NULL
;
4583 default_used
= FALSE
;
4584 if (codepage_sets_default_used(font
->codepage
))
4585 default_used_pointer
= &default_used
;
4586 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4589 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4590 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4591 return get_GSUB_vert_glyph(font
,ret
);
4594 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
4596 if (glyph
< 0x100) glyph
+= 0xf000;
4597 /* there is a number of old pre-Unicode "broken" TTFs, which
4598 do have symbols at U+00XX instead of U+f0XX */
4599 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
4600 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
4602 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4604 return get_GSUB_vert_glyph(font
,glyphId
);
4607 /*************************************************************
4608 * WineEngGetGlyphIndices
4611 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4612 LPWORD pgi
, DWORD flags
)
4616 BOOL got_default
= FALSE
;
4618 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
4620 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4624 for(i
= 0; i
< count
; i
++)
4626 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4631 if (FT_IS_SFNT(font
->ft_face
))
4633 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4634 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4639 WineEngGetTextMetrics(font
, &textm
);
4640 default_char
= textm
.tmDefaultChar
;
4644 pgi
[i
] = default_char
;
4650 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4652 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4653 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4656 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4658 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4659 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4662 /*************************************************************
4663 * WineEngGetGlyphOutline
4665 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4666 * except that the first parameter is the HWINEENGFONT of the font in
4667 * question rather than an HDC.
4670 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4671 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4674 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4675 FT_Face ft_face
= incoming_font
->ft_face
;
4676 GdiFont
*font
= incoming_font
;
4677 FT_UInt glyph_index
;
4678 DWORD width
, height
, pitch
, needed
= 0;
4679 FT_Bitmap ft_bitmap
;
4681 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4683 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4684 double widthRatio
= 1.0;
4685 FT_Matrix transMat
= identityMat
;
4686 FT_Matrix transMatUnrotated
;
4687 BOOL needsTransform
= FALSE
;
4688 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4689 UINT original_index
;
4691 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4692 buflen
, buf
, lpmat
);
4694 TRACE("font transform %f %f %f %f\n",
4695 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4696 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4699 EnterCriticalSection( &freetype_cs
);
4701 if(format
& GGO_GLYPH_INDEX
) {
4702 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4703 original_index
= glyph
;
4704 format
&= ~GGO_GLYPH_INDEX
;
4706 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4707 ft_face
= font
->ft_face
;
4708 original_index
= glyph_index
;
4711 if(format
& GGO_UNHINTED
) {
4712 load_flags
|= FT_LOAD_NO_HINTING
;
4713 format
&= ~GGO_UNHINTED
;
4716 /* tategaki never appears to happen to lower glyph index */
4717 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4720 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4721 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4722 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4723 font
->gmsize
* sizeof(GM
*));
4725 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4726 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
4728 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4729 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4730 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4731 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4732 LeaveCriticalSection( &freetype_cs
);
4733 return 1; /* FIXME */
4737 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4738 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4740 /* Scaling factor */
4745 WineEngGetTextMetrics(font
, &tm
);
4747 widthRatio
= (double)font
->aveWidth
;
4748 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4751 widthRatio
= font
->scale_y
;
4753 /* Scaling transform */
4754 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4757 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4760 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4762 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4763 needsTransform
= TRUE
;
4766 /* Slant transform */
4767 if (font
->fake_italic
) {
4770 slantMat
.xx
= (1 << 16);
4771 slantMat
.xy
= ((1 << 16) >> 2);
4773 slantMat
.yy
= (1 << 16);
4774 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4775 needsTransform
= TRUE
;
4778 /* Rotation transform */
4779 transMatUnrotated
= transMat
;
4780 if(font
->orientation
&& !tategaki
) {
4781 FT_Matrix rotationMat
;
4783 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4784 pFT_Vector_Unit(&vecAngle
, angle
);
4785 rotationMat
.xx
= vecAngle
.x
;
4786 rotationMat
.xy
= -vecAngle
.y
;
4787 rotationMat
.yx
= -rotationMat
.xy
;
4788 rotationMat
.yy
= rotationMat
.xx
;
4790 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4791 needsTransform
= TRUE
;
4794 /* World transform */
4795 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4798 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4799 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4800 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4801 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4802 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4803 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4804 needsTransform
= TRUE
;
4807 /* Extra transformation specified by caller */
4808 if (!is_identity_MAT2(lpmat
))
4811 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4812 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
4813 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
4814 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4815 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4816 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4817 needsTransform
= TRUE
;
4820 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4821 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4822 format
== GGO_GRAY8_BITMAP
))
4824 load_flags
|= FT_LOAD_NO_BITMAP
;
4827 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4830 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4831 LeaveCriticalSection( &freetype_cs
);
4835 if(!needsTransform
) {
4836 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4837 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4838 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
4840 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4841 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4842 ft_face
->glyph
->metrics
.height
) & -64;
4843 lpgm
->gmCellIncX
= adv
;
4844 lpgm
->gmCellIncY
= 0;
4851 for(xc
= 0; xc
< 2; xc
++) {
4852 for(yc
= 0; yc
< 2; yc
++) {
4853 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4854 xc
* ft_face
->glyph
->metrics
.width
);
4855 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4856 yc
* ft_face
->glyph
->metrics
.height
;
4857 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4858 pFT_Vector_Transform(&vec
, &transMat
);
4859 if(xc
== 0 && yc
== 0) {
4860 left
= right
= vec
.x
;
4861 top
= bottom
= vec
.y
;
4863 if(vec
.x
< left
) left
= vec
.x
;
4864 else if(vec
.x
> right
) right
= vec
.x
;
4865 if(vec
.y
< bottom
) bottom
= vec
.y
;
4866 else if(vec
.y
> top
) top
= vec
.y
;
4871 right
= (right
+ 63) & -64;
4872 bottom
= bottom
& -64;
4873 top
= (top
+ 63) & -64;
4875 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4876 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4878 pFT_Vector_Transform(&vec
, &transMat
);
4879 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4880 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4882 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4884 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4885 adv
= (vec
.x
+63) >> 6;
4889 bbx
= (right
- left
) >> 6;
4890 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4891 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4892 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4893 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4895 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4896 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4897 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4899 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4900 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
4902 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4903 FONT_GM(font
,original_index
)->adv
= adv
;
4904 FONT_GM(font
,original_index
)->lsb
= lsb
;
4905 FONT_GM(font
,original_index
)->bbx
= bbx
;
4906 FONT_GM(font
,original_index
)->init
= TRUE
;
4909 if(format
== GGO_METRICS
)
4911 LeaveCriticalSection( &freetype_cs
);
4912 return 1; /* FIXME */
4915 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
4916 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4917 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4918 format
== GGO_GRAY8_BITMAP
))
4920 TRACE("loaded a bitmap\n");
4921 LeaveCriticalSection( &freetype_cs
);
4927 width
= lpgm
->gmBlackBoxX
;
4928 height
= lpgm
->gmBlackBoxY
;
4929 pitch
= ((width
+ 31) >> 5) << 2;
4930 needed
= pitch
* height
;
4932 if(!buf
|| !buflen
) break;
4934 switch(ft_face
->glyph
->format
) {
4935 case ft_glyph_format_bitmap
:
4937 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4938 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4939 INT h
= ft_face
->glyph
->bitmap
.rows
;
4941 memcpy(dst
, src
, w
);
4942 src
+= ft_face
->glyph
->bitmap
.pitch
;
4948 case ft_glyph_format_outline
:
4949 ft_bitmap
.width
= width
;
4950 ft_bitmap
.rows
= height
;
4951 ft_bitmap
.pitch
= pitch
;
4952 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4953 ft_bitmap
.buffer
= buf
;
4956 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4958 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4960 /* Note: FreeType will only set 'black' bits for us. */
4961 memset(buf
, 0, needed
);
4962 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4966 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4967 LeaveCriticalSection( &freetype_cs
);
4972 case GGO_GRAY2_BITMAP
:
4973 case GGO_GRAY4_BITMAP
:
4974 case GGO_GRAY8_BITMAP
:
4975 case WINE_GGO_GRAY16_BITMAP
:
4977 unsigned int mult
, row
, col
;
4980 width
= lpgm
->gmBlackBoxX
;
4981 height
= lpgm
->gmBlackBoxY
;
4982 pitch
= (width
+ 3) / 4 * 4;
4983 needed
= pitch
* height
;
4985 if(!buf
|| !buflen
) break;
4987 switch(ft_face
->glyph
->format
) {
4988 case ft_glyph_format_bitmap
:
4990 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4991 INT h
= ft_face
->glyph
->bitmap
.rows
;
4993 memset( buf
, 0, needed
);
4995 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
4996 if (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) dst
[x
] = 0xff;
4997 src
+= ft_face
->glyph
->bitmap
.pitch
;
5000 LeaveCriticalSection( &freetype_cs
);
5003 case ft_glyph_format_outline
:
5005 ft_bitmap
.width
= width
;
5006 ft_bitmap
.rows
= height
;
5007 ft_bitmap
.pitch
= pitch
;
5008 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5009 ft_bitmap
.buffer
= buf
;
5012 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5014 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5016 memset(ft_bitmap
.buffer
, 0, buflen
);
5018 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5020 if(format
== GGO_GRAY2_BITMAP
)
5022 else if(format
== GGO_GRAY4_BITMAP
)
5024 else if(format
== GGO_GRAY8_BITMAP
)
5026 else /* format == WINE_GGO_GRAY16_BITMAP */
5028 LeaveCriticalSection( &freetype_cs
);
5034 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5035 LeaveCriticalSection( &freetype_cs
);
5040 for(row
= 0; row
< height
; row
++) {
5042 for(col
= 0; col
< width
; col
++, ptr
++) {
5043 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
5050 case WINE_GGO_HRGB_BITMAP
:
5051 case WINE_GGO_HBGR_BITMAP
:
5052 case WINE_GGO_VRGB_BITMAP
:
5053 case WINE_GGO_VBGR_BITMAP
:
5054 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5056 switch (ft_face
->glyph
->format
)
5058 case FT_GLYPH_FORMAT_BITMAP
:
5063 width
= lpgm
->gmBlackBoxX
;
5064 height
= lpgm
->gmBlackBoxY
;
5066 needed
= pitch
* height
;
5068 if (!buf
|| !buflen
) break;
5070 memset(buf
, 0, buflen
);
5072 src
= ft_face
->glyph
->bitmap
.buffer
;
5073 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5075 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5078 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5080 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
5081 ((unsigned int *)dst
)[x
] = ~0u;
5090 case FT_GLYPH_FORMAT_OUTLINE
:
5094 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5095 INT x_shift
, y_shift
;
5097 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5098 FT_Render_Mode render_mode
=
5099 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5100 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5102 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5104 if ( render_mode
== FT_RENDER_MODE_LCD
)
5106 lpgm
->gmBlackBoxX
+= 2;
5107 lpgm
->gmptGlyphOrigin
.x
-= 1;
5111 lpgm
->gmBlackBoxY
+= 2;
5112 lpgm
->gmptGlyphOrigin
.y
+= 1;
5116 width
= lpgm
->gmBlackBoxX
;
5117 height
= lpgm
->gmBlackBoxY
;
5119 needed
= pitch
* height
;
5121 if (!buf
|| !buflen
) break;
5123 memset(buf
, 0, buflen
);
5125 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5127 if ( needsTransform
)
5128 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5130 if ( pFT_Library_SetLcdFilter
)
5131 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5132 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5134 src
= ft_face
->glyph
->bitmap
.buffer
;
5135 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5136 src_width
= ft_face
->glyph
->bitmap
.width
;
5137 src_height
= ft_face
->glyph
->bitmap
.rows
;
5139 if ( render_mode
== FT_RENDER_MODE_LCD
)
5147 rgb_interval
= src_pitch
;
5152 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5153 if ( x_shift
< 0 ) x_shift
= 0;
5154 if ( x_shift
+ (src_width
/ hmul
) > width
)
5155 x_shift
= width
- (src_width
/ hmul
);
5157 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5158 if ( y_shift
< 0 ) y_shift
= 0;
5159 if ( y_shift
+ (src_height
/ vmul
) > height
)
5160 y_shift
= height
- (src_height
/ vmul
);
5162 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5163 while ( src_height
)
5165 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5169 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5170 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5171 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5172 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5176 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5177 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5178 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5179 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5182 src
+= src_pitch
* vmul
;
5191 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5192 LeaveCriticalSection ( &freetype_cs
);
5199 LeaveCriticalSection( &freetype_cs
);
5205 int contour
, point
= 0, first_pt
;
5206 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5207 TTPOLYGONHEADER
*pph
;
5209 DWORD pph_start
, cpfx
, type
;
5211 if(buflen
== 0) buf
= NULL
;
5213 if (needsTransform
&& buf
) {
5214 pFT_Outline_Transform(outline
, &transMat
);
5217 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5219 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5222 pph
->dwType
= TT_POLYGON_TYPE
;
5223 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5225 needed
+= sizeof(*pph
);
5227 while(point
<= outline
->contours
[contour
]) {
5228 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5229 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5230 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5234 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5237 } while(point
<= outline
->contours
[contour
] &&
5238 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5239 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5240 /* At the end of a contour Windows adds the start point, but
5242 if(point
> outline
->contours
[contour
] &&
5243 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5245 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5247 } else if(point
<= outline
->contours
[contour
] &&
5248 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5249 /* add closing pt for bezier */
5251 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5259 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5262 pph
->cb
= needed
- pph_start
;
5268 /* Convert the quadratic Beziers to cubic Beziers.
5269 The parametric eqn for a cubic Bezier is, from PLRM:
5270 r(t) = at^3 + bt^2 + ct + r0
5271 with the control points:
5276 A quadratic Bezier has the form:
5277 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5279 So equating powers of t leads to:
5280 r1 = 2/3 p1 + 1/3 p0
5281 r2 = 2/3 p1 + 1/3 p2
5282 and of course r0 = p0, r3 = p2
5285 int contour
, point
= 0, first_pt
;
5286 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5287 TTPOLYGONHEADER
*pph
;
5289 DWORD pph_start
, cpfx
, type
;
5290 FT_Vector cubic_control
[4];
5291 if(buflen
== 0) buf
= NULL
;
5293 if (needsTransform
&& buf
) {
5294 pFT_Outline_Transform(outline
, &transMat
);
5297 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5299 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5302 pph
->dwType
= TT_POLYGON_TYPE
;
5303 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5305 needed
+= sizeof(*pph
);
5307 while(point
<= outline
->contours
[contour
]) {
5308 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5309 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5310 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5313 if(type
== TT_PRIM_LINE
) {
5315 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5319 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5322 /* FIXME: Possible optimization in endpoint calculation
5323 if there are two consecutive curves */
5324 cubic_control
[0] = outline
->points
[point
-1];
5325 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5326 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5327 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5328 cubic_control
[0].x
>>= 1;
5329 cubic_control
[0].y
>>= 1;
5331 if(point
+1 > outline
->contours
[contour
])
5332 cubic_control
[3] = outline
->points
[first_pt
];
5334 cubic_control
[3] = outline
->points
[point
+1];
5335 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5336 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5337 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5338 cubic_control
[3].x
>>= 1;
5339 cubic_control
[3].y
>>= 1;
5342 /* r1 = 1/3 p0 + 2/3 p1
5343 r2 = 1/3 p2 + 2/3 p1 */
5344 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5345 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5346 cubic_control
[2] = cubic_control
[1];
5347 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5348 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5349 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5350 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5352 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5353 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5354 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5359 } while(point
<= outline
->contours
[contour
] &&
5360 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5361 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5362 /* At the end of a contour Windows adds the start point,
5363 but only for Beziers and we've already done that.
5365 if(point
<= outline
->contours
[contour
] &&
5366 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5367 /* This is the closing pt of a bezier, but we've already
5368 added it, so just inc point and carry on */
5375 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5378 pph
->cb
= needed
- pph_start
;
5384 FIXME("Unsupported format %d\n", format
);
5385 LeaveCriticalSection( &freetype_cs
);
5388 LeaveCriticalSection( &freetype_cs
);
5392 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5394 FT_Face ft_face
= font
->ft_face
;
5395 #ifdef HAVE_FREETYPE_FTWINFNT_H
5396 FT_WinFNT_HeaderRec winfnt_header
;
5398 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5399 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5400 font
->potm
->otmSize
= size
;
5402 #define TM font->potm->otmTextMetrics
5403 #ifdef HAVE_FREETYPE_FTWINFNT_H
5404 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5406 TM
.tmHeight
= winfnt_header
.pixel_height
;
5407 TM
.tmAscent
= winfnt_header
.ascent
;
5408 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5409 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5410 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5411 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5412 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5413 TM
.tmWeight
= winfnt_header
.weight
;
5415 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5416 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5417 TM
.tmFirstChar
= winfnt_header
.first_char
;
5418 TM
.tmLastChar
= winfnt_header
.last_char
;
5419 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5420 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5421 TM
.tmItalic
= winfnt_header
.italic
;
5422 TM
.tmUnderlined
= font
->underline
;
5423 TM
.tmStruckOut
= font
->strikeout
;
5424 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5425 TM
.tmCharSet
= winfnt_header
.charset
;
5430 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5431 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5432 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5433 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5434 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5435 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5436 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5437 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5439 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5440 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5442 TM
.tmLastChar
= 255;
5443 TM
.tmDefaultChar
= 32;
5444 TM
.tmBreakChar
= 32;
5445 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5446 TM
.tmUnderlined
= font
->underline
;
5447 TM
.tmStruckOut
= font
->strikeout
;
5448 /* NB inverted meaning of TMPF_FIXED_PITCH */
5449 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5450 TM
.tmCharSet
= font
->charset
;
5458 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5460 double scale_x
, scale_y
;
5464 scale_x
= (double)font
->aveWidth
;
5465 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5468 scale_x
= font
->scale_y
;
5470 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5471 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5473 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5474 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5476 SCALE_Y(ptm
->tmHeight
);
5477 SCALE_Y(ptm
->tmAscent
);
5478 SCALE_Y(ptm
->tmDescent
);
5479 SCALE_Y(ptm
->tmInternalLeading
);
5480 SCALE_Y(ptm
->tmExternalLeading
);
5481 SCALE_Y(ptm
->tmOverhang
);
5483 SCALE_X(ptm
->tmAveCharWidth
);
5484 SCALE_X(ptm
->tmMaxCharWidth
);
5490 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5492 double scale_x
, scale_y
;
5496 scale_x
= (double)font
->aveWidth
;
5497 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5500 scale_x
= font
->scale_y
;
5502 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5503 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5505 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5507 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5508 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5510 SCALE_Y(potm
->otmAscent
);
5511 SCALE_Y(potm
->otmDescent
);
5512 SCALE_Y(potm
->otmLineGap
);
5513 SCALE_Y(potm
->otmsCapEmHeight
);
5514 SCALE_Y(potm
->otmsXHeight
);
5515 SCALE_Y(potm
->otmrcFontBox
.top
);
5516 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5517 SCALE_X(potm
->otmrcFontBox
.left
);
5518 SCALE_X(potm
->otmrcFontBox
.right
);
5519 SCALE_Y(potm
->otmMacAscent
);
5520 SCALE_Y(potm
->otmMacDescent
);
5521 SCALE_Y(potm
->otmMacLineGap
);
5522 SCALE_X(potm
->otmptSubscriptSize
.x
);
5523 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5524 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5525 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5526 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5527 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5528 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5529 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5530 SCALE_Y(potm
->otmsStrikeoutSize
);
5531 SCALE_Y(potm
->otmsStrikeoutPosition
);
5532 SCALE_Y(potm
->otmsUnderscoreSize
);
5533 SCALE_Y(potm
->otmsUnderscorePosition
);
5539 /*************************************************************
5540 * WineEngGetTextMetrics
5543 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5546 EnterCriticalSection( &freetype_cs
);
5548 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5549 if(!get_bitmap_text_metrics(font
))
5551 LeaveCriticalSection( &freetype_cs
);
5555 /* Make sure that the font has sane width/height ratio */
5558 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
5560 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
5566 *ptm
= font
->potm
->otmTextMetrics
;
5567 scale_font_metrics(font
, ptm
);
5568 LeaveCriticalSection( &freetype_cs
);
5572 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5576 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5578 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
5584 /*************************************************************
5585 * WineEngGetOutlineTextMetrics
5588 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5589 OUTLINETEXTMETRICW
*potm
)
5591 FT_Face ft_face
= font
->ft_face
;
5592 UINT needed
, lenfam
, lensty
, ret
;
5594 TT_HoriHeader
*pHori
;
5595 TT_Postscript
*pPost
;
5596 FT_Fixed x_scale
, y_scale
;
5597 WCHAR
*family_nameW
, *style_nameW
;
5598 static const WCHAR spaceW
[] = {' ', '\0'};
5600 INT ascent
, descent
;
5602 TRACE("font=%p\n", font
);
5604 if(!FT_IS_SCALABLE(ft_face
))
5608 EnterCriticalSection( &freetype_cs
);
5611 if(cbSize
>= font
->potm
->otmSize
)
5613 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5614 scale_outline_font_metrics(font
, potm
);
5616 LeaveCriticalSection( &freetype_cs
);
5617 return font
->potm
->otmSize
;
5621 needed
= sizeof(*potm
);
5623 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5624 family_nameW
= strdupW(font
->name
);
5626 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5628 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5629 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5630 style_nameW
, lensty
/sizeof(WCHAR
));
5632 /* These names should be read from the TT name table */
5634 /* length of otmpFamilyName */
5637 /* length of otmpFaceName */
5638 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5639 needed
+= lenfam
; /* just the family name */
5641 needed
+= lenfam
+ lensty
; /* family + " " + style */
5644 /* length of otmpStyleName */
5647 /* length of otmpFullName */
5648 needed
+= lenfam
+ lensty
;
5651 x_scale
= ft_face
->size
->metrics
.x_scale
;
5652 y_scale
= ft_face
->size
->metrics
.y_scale
;
5654 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5656 FIXME("Can't find OS/2 table - not TT font?\n");
5661 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5663 FIXME("Can't find HHEA table - not TT font?\n");
5668 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5670 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",
5671 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5672 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5673 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5674 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5675 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5677 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5678 font
->potm
->otmSize
= needed
;
5680 #define TM font->potm->otmTextMetrics
5682 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5683 ascent
= pHori
->Ascender
;
5684 descent
= -pHori
->Descender
;
5686 ascent
= pOS2
->usWinAscent
;
5687 descent
= pOS2
->usWinDescent
;
5691 TM
.tmAscent
= font
->yMax
;
5692 TM
.tmDescent
= -font
->yMin
;
5693 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5695 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5696 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5697 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5698 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5701 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5704 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5706 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5707 ((ascent
+ descent
) -
5708 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5710 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5711 if (TM
.tmAveCharWidth
== 0) {
5712 TM
.tmAveCharWidth
= 1;
5714 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5715 TM
.tmWeight
= FW_REGULAR
;
5716 if (font
->fake_bold
)
5717 TM
.tmWeight
= FW_BOLD
;
5720 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
5722 if (pOS2
->usWeightClass
> FW_MEDIUM
)
5723 TM
.tmWeight
= pOS2
->usWeightClass
;
5725 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
5726 TM
.tmWeight
= pOS2
->usWeightClass
;
5729 TM
.tmDigitizedAspectX
= 300;
5730 TM
.tmDigitizedAspectY
= 300;
5731 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5732 * symbol range to 0 - f0ff
5735 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
5740 case 1257: /* Baltic */
5741 TM
.tmLastChar
= 0xf8fd;
5744 TM
.tmLastChar
= 0xf0ff;
5746 TM
.tmBreakChar
= 0x20;
5747 TM
.tmDefaultChar
= 0x1f;
5751 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
5752 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
5754 if(pOS2
->usFirstCharIndex
<= 1)
5755 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
5756 else if (pOS2
->usFirstCharIndex
> 0xff)
5757 TM
.tmBreakChar
= 0x20;
5759 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
5760 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
5762 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5763 TM
.tmUnderlined
= font
->underline
;
5764 TM
.tmStruckOut
= font
->strikeout
;
5766 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5767 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5768 (pOS2
->version
== 0xFFFFU
||
5769 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5770 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5772 TM
.tmPitchAndFamily
= 0;
5774 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
5776 case PAN_FAMILY_SCRIPT
:
5777 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5780 case PAN_FAMILY_DECORATIVE
:
5781 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5786 case PAN_FAMILY_TEXT_DISPLAY
:
5787 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
5788 /* which is clearly not what the panose spec says. */
5790 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
5791 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
5792 TM
.tmPitchAndFamily
= FF_MODERN
;
5795 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
5800 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5803 case PAN_SERIF_COVE
:
5804 case PAN_SERIF_OBTUSE_COVE
:
5805 case PAN_SERIF_SQUARE_COVE
:
5806 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
5807 case PAN_SERIF_SQUARE
:
5808 case PAN_SERIF_THIN
:
5809 case PAN_SERIF_BONE
:
5810 case PAN_SERIF_EXAGGERATED
:
5811 case PAN_SERIF_TRIANGLE
:
5812 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5815 case PAN_SERIF_NORMAL_SANS
:
5816 case PAN_SERIF_OBTUSE_SANS
:
5817 case PAN_SERIF_PERP_SANS
:
5818 case PAN_SERIF_FLARED
:
5819 case PAN_SERIF_ROUNDED
:
5820 TM
.tmPitchAndFamily
|= FF_SWISS
;
5827 if(FT_IS_SCALABLE(ft_face
))
5828 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5830 if(FT_IS_SFNT(ft_face
))
5832 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5833 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5835 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5838 TM
.tmCharSet
= font
->charset
;
5840 font
->potm
->otmFiller
= 0;
5841 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5842 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5843 font
->potm
->otmfsType
= pOS2
->fsType
;
5844 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5845 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5846 font
->potm
->otmItalicAngle
= 0; /* POST table */
5847 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5848 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5849 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5850 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5851 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5852 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5853 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5854 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5855 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5856 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5857 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5858 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5859 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5860 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5861 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5862 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5863 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5864 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5865 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5866 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5867 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5868 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5869 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5870 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5872 font
->potm
->otmsUnderscoreSize
= 0;
5873 font
->potm
->otmsUnderscorePosition
= 0;
5875 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5876 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5880 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5881 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5882 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5883 strcpyW((WCHAR
*)cp
, family_nameW
);
5885 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5886 strcpyW((WCHAR
*)cp
, style_nameW
);
5888 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5889 strcpyW((WCHAR
*)cp
, family_nameW
);
5890 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5891 strcatW((WCHAR
*)cp
, spaceW
);
5892 strcatW((WCHAR
*)cp
, style_nameW
);
5893 cp
+= lenfam
+ lensty
;
5896 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5897 strcpyW((WCHAR
*)cp
, family_nameW
);
5898 strcatW((WCHAR
*)cp
, spaceW
);
5899 strcatW((WCHAR
*)cp
, style_nameW
);
5902 if(potm
&& needed
<= cbSize
)
5904 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5905 scale_outline_font_metrics(font
, potm
);
5909 HeapFree(GetProcessHeap(), 0, style_nameW
);
5910 HeapFree(GetProcessHeap(), 0, family_nameW
);
5912 LeaveCriticalSection( &freetype_cs
);
5916 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5918 HFONTLIST
*hfontlist
;
5919 child
->font
= alloc_font();
5920 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5921 if(!child
->font
->ft_face
)
5923 free_font(child
->font
);
5928 child
->font
->font_desc
= font
->font_desc
;
5929 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5930 child
->font
->orientation
= font
->orientation
;
5931 child
->font
->scale_y
= font
->scale_y
;
5932 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5933 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5934 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
5935 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5936 child
->font
->base_font
= font
;
5937 list_add_head(&child_font_list
, &child
->font
->entry
);
5938 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5942 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5945 CHILD_FONT
*child_font
;
5948 font
= font
->base_font
;
5950 *linked_font
= font
;
5952 if((*glyph
= get_glyph_index(font
, c
)))
5955 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5957 if(!child_font
->font
)
5958 if(!load_child_font(font
, child_font
))
5961 if(!child_font
->font
->ft_face
)
5963 g
= get_glyph_index(child_font
->font
, c
);
5967 *linked_font
= child_font
->font
;
5974 /*************************************************************
5975 * WineEngGetCharWidth
5978 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5981 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5984 FT_UInt glyph_index
;
5985 GdiFont
*linked_font
;
5987 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5990 EnterCriticalSection( &freetype_cs
);
5991 for(c
= firstChar
; c
<= lastChar
; c
++) {
5992 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5993 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5994 &gm
, 0, NULL
, &identity
);
5995 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5997 LeaveCriticalSection( &freetype_cs
);
6001 /*************************************************************
6002 * WineEngGetCharABCWidths
6005 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6008 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6011 FT_UInt glyph_index
;
6012 GdiFont
*linked_font
;
6014 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
6016 if(!FT_IS_SCALABLE(font
->ft_face
))
6020 EnterCriticalSection( &freetype_cs
);
6022 for(c
= firstChar
; c
<= lastChar
; c
++) {
6023 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
6024 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6025 &gm
, 0, NULL
, &identity
);
6026 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6027 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6028 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6029 FONT_GM(linked_font
,glyph_index
)->bbx
;
6031 LeaveCriticalSection( &freetype_cs
);
6035 /*************************************************************
6036 * WineEngGetCharABCWidthsFloat
6039 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
6041 static const MAT2 identity
= {{0,1}, {0,0}, {0,0}, {0,1}};
6044 FT_UInt glyph_index
;
6045 GdiFont
*linked_font
;
6047 TRACE("%p, %d, %d, %p\n", font
, first
, last
, buffer
);
6050 EnterCriticalSection( &freetype_cs
);
6052 for (c
= first
; c
<= last
; c
++)
6054 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
6055 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6056 &gm
, 0, NULL
, &identity
);
6057 buffer
[c
- first
].abcfA
= FONT_GM(linked_font
, glyph_index
)->lsb
;
6058 buffer
[c
- first
].abcfB
= FONT_GM(linked_font
, glyph_index
)->bbx
;
6059 buffer
[c
- first
].abcfC
= FONT_GM(linked_font
, glyph_index
)->adv
-
6060 FONT_GM(linked_font
, glyph_index
)->lsb
-
6061 FONT_GM(linked_font
, glyph_index
)->bbx
;
6063 LeaveCriticalSection( &freetype_cs
);
6067 /*************************************************************
6068 * WineEngGetCharABCWidthsI
6071 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6074 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6077 FT_UInt glyph_index
;
6078 GdiFont
*linked_font
;
6080 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
6084 EnterCriticalSection( &freetype_cs
);
6086 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
6088 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6089 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6090 &gm
, 0, NULL
, &identity
);
6091 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6092 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6093 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6094 - FONT_GM(linked_font
,c
)->bbx
;
6097 for(c
= 0; c
< count
; c
++) {
6098 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6099 &gm
, 0, NULL
, &identity
);
6100 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6101 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6102 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6103 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6106 LeaveCriticalSection( &freetype_cs
);
6110 /*************************************************************
6111 * WineEngGetTextExtentExPoint
6114 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6115 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6117 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6122 FT_UInt glyph_index
;
6123 GdiFont
*linked_font
;
6125 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
6129 EnterCriticalSection( &freetype_cs
);
6132 WineEngGetTextMetrics(font
, &tm
);
6133 size
->cy
= tm
.tmHeight
;
6135 for(idx
= 0; idx
< count
; idx
++) {
6136 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
6137 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6138 &gm
, 0, NULL
, &identity
);
6139 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6141 if (! pnfit
|| ext
<= max_ext
) {
6151 LeaveCriticalSection( &freetype_cs
);
6152 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6156 /*************************************************************
6157 * WineEngGetTextExtentExPointI
6160 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6161 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6163 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6169 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
6172 EnterCriticalSection( &freetype_cs
);
6175 WineEngGetTextMetrics(font
, &tm
);
6176 size
->cy
= tm
.tmHeight
;
6178 for(idx
= 0; idx
< count
; idx
++) {
6179 WineEngGetGlyphOutline(font
, indices
[idx
],
6180 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
6182 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
6184 if (! pnfit
|| ext
<= max_ext
) {
6194 LeaveCriticalSection( &freetype_cs
);
6195 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6199 /*************************************************************
6200 * WineEngGetFontData
6203 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6206 FT_Face ft_face
= font
->ft_face
;
6210 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6211 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6212 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6214 if(!FT_IS_SFNT(ft_face
))
6222 if(table
) { /* MS tags differ in endianness from FT ones */
6223 table
= table
>> 24 | table
<< 24 |
6224 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
6227 /* make sure value of len is the value freetype says it needs */
6230 FT_ULong needed
= 0;
6231 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
6232 if( !err
&& needed
< len
) len
= needed
;
6234 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
6237 TRACE("Can't find table %c%c%c%c\n",
6238 /* bytes were reversed */
6239 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
6240 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
6246 /*************************************************************
6247 * WineEngGetTextFace
6250 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6252 INT n
= strlenW(font
->name
) + 1;
6254 lstrcpynW(str
, font
->name
, count
);
6255 return min(count
, n
);
6260 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6262 if (fs
) *fs
= font
->fs
;
6263 return font
->charset
;
6266 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6268 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6269 struct list
*first_hfont
;
6273 EnterCriticalSection( &freetype_cs
);
6274 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6275 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6276 if(font
== linked_font
)
6277 *new_hfont
= dc
->hFont
;
6280 first_hfont
= list_head(&linked_font
->hfontlist
);
6281 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6283 LeaveCriticalSection( &freetype_cs
);
6287 /* Retrieve a list of supported Unicode ranges for a given font.
6288 * Can be called with NULL gs to calculate the buffer size. Returns
6289 * the number of ranges found.
6291 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6293 DWORD num_ranges
= 0;
6295 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6298 FT_ULong char_code
, char_code_prev
;
6301 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6303 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6304 face
->num_glyphs
, glyph_code
, char_code
);
6306 if (!glyph_code
) return 0;
6310 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6311 gs
->ranges
[0].cGlyphs
= 0;
6312 gs
->cGlyphsSupported
= 0;
6318 if (char_code
< char_code_prev
)
6320 ERR("expected increasing char code from FT_Get_Next_Char\n");
6323 if (char_code
- char_code_prev
> 1)
6328 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6329 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6330 gs
->cGlyphsSupported
++;
6335 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6336 gs
->cGlyphsSupported
++;
6338 char_code_prev
= char_code
;
6339 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6343 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6348 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6351 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
6353 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6356 glyphset
->cbThis
= size
;
6357 glyphset
->cRanges
= num_ranges
;
6358 glyphset
->flAccel
= 0;
6363 /*************************************************************
6366 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6370 EnterCriticalSection( &freetype_cs
);
6371 ret
= !list_empty(&font
->child_fonts
);
6372 LeaveCriticalSection( &freetype_cs
);
6376 static BOOL
is_hinting_enabled(void)
6378 /* Use the >= 2.2.0 function if available */
6379 if(pFT_Get_TrueType_Engine_Type
)
6381 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6382 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6384 #ifdef FT_DRIVER_HAS_HINTER
6389 /* otherwise if we've been compiled with < 2.2.0 headers
6390 use the internal macro */
6391 mod
= pFT_Get_Module(library
, "truetype");
6392 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6400 static BOOL
is_subpixel_rendering_enabled( void )
6402 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6403 return pFT_Library_SetLcdFilter
&&
6404 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6410 /*************************************************************************
6411 * GetRasterizerCaps (GDI32.@)
6413 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6415 static int hinting
= -1;
6416 static int subpixel
= -1;
6420 hinting
= is_hinting_enabled();
6421 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6424 if ( subpixel
== -1 )
6426 subpixel
= is_subpixel_rendering_enabled();
6427 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6430 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6431 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6433 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6434 lprs
->nLanguageID
= 0;
6438 /*************************************************************
6439 * WineEngRealizationInfo
6441 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6443 FIXME("(%p, %p): stub!\n", font
, info
);
6446 if(FT_IS_SCALABLE(font
->ft_face
))
6449 info
->cache_num
= font
->cache_num
;
6450 info
->unknown2
= -1;
6454 /*************************************************************************
6455 * Kerning support for TrueType fonts
6457 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6459 struct TT_kern_table
6465 struct TT_kern_subtable
6474 USHORT horizontal
: 1;
6476 USHORT cross_stream
: 1;
6477 USHORT override
: 1;
6478 USHORT reserved1
: 4;
6484 struct TT_format0_kern_subtable
6488 USHORT entrySelector
;
6499 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6500 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6501 const USHORT
*glyph_to_char
,
6502 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6505 const struct TT_kern_pair
*tt_kern_pair
;
6507 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6509 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6511 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6512 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6513 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6515 if (!kern_pair
|| !cPairs
)
6518 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6520 nPairs
= min(nPairs
, cPairs
);
6522 for (i
= 0; i
< nPairs
; i
++)
6524 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6525 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6526 /* this algorithm appears to better match what Windows does */
6527 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6528 if (kern_pair
->iKernAmount
< 0)
6530 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6531 kern_pair
->iKernAmount
-= font
->ppem
;
6533 else if (kern_pair
->iKernAmount
> 0)
6535 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6536 kern_pair
->iKernAmount
+= font
->ppem
;
6538 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6540 TRACE("left %u right %u value %d\n",
6541 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6545 TRACE("copied %u entries\n", nPairs
);
6549 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6553 const struct TT_kern_table
*tt_kern_table
;
6554 const struct TT_kern_subtable
*tt_kern_subtable
;
6556 USHORT
*glyph_to_char
;
6559 EnterCriticalSection( &freetype_cs
);
6560 if (font
->total_kern_pairs
!= (DWORD
)-1)
6562 if (cPairs
&& kern_pair
)
6564 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6565 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6566 LeaveCriticalSection( &freetype_cs
);
6569 LeaveCriticalSection( &freetype_cs
);
6570 return font
->total_kern_pairs
;
6573 font
->total_kern_pairs
= 0;
6575 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6577 if (length
== GDI_ERROR
)
6579 TRACE("no kerning data in the font\n");
6580 LeaveCriticalSection( &freetype_cs
);
6584 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6587 WARN("Out of memory\n");
6588 LeaveCriticalSection( &freetype_cs
);
6592 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6594 /* build a glyph index to char code map */
6595 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6598 WARN("Out of memory allocating a glyph index to char code map\n");
6599 HeapFree(GetProcessHeap(), 0, buf
);
6600 LeaveCriticalSection( &freetype_cs
);
6604 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6610 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6612 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6613 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6617 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6619 /* FIXME: This doesn't match what Windows does: it does some fancy
6620 * things with duplicate glyph index to char code mappings, while
6621 * we just avoid overriding existing entries.
6623 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6624 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6626 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6633 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6634 for (n
= 0; n
<= 65535; n
++)
6635 glyph_to_char
[n
] = (USHORT
)n
;
6638 tt_kern_table
= buf
;
6639 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6640 TRACE("version %u, nTables %u\n",
6641 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6643 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6645 for (i
= 0; i
< nTables
; i
++)
6647 struct TT_kern_subtable tt_kern_subtable_copy
;
6649 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6650 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6651 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6653 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6654 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6655 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6657 /* According to the TrueType specification this is the only format
6658 * that will be properly interpreted by Windows and OS/2
6660 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6662 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6664 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6665 glyph_to_char
, NULL
, 0);
6666 font
->total_kern_pairs
+= new_chunk
;
6668 if (!font
->kern_pairs
)
6669 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6670 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6672 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6673 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6675 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6676 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6679 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6681 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6684 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6685 HeapFree(GetProcessHeap(), 0, buf
);
6687 if (cPairs
&& kern_pair
)
6689 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6690 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6691 LeaveCriticalSection( &freetype_cs
);
6694 LeaveCriticalSection( &freetype_cs
);
6695 return font
->total_kern_pairs
;
6698 #else /* HAVE_FREETYPE */
6700 /*************************************************************************/
6702 BOOL
WineEngInit(void)
6706 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6710 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6715 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6720 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6721 LPWORD pgi
, DWORD flags
)
6726 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6727 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6730 ERR("called but we don't have FreeType\n");
6734 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6736 ERR("called but we don't have FreeType\n");
6740 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6741 OUTLINETEXTMETRICW
*potm
)
6743 ERR("called but we don't have FreeType\n");
6747 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6750 ERR("called but we don't have FreeType\n");
6754 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6757 ERR("called but we don't have FreeType\n");
6761 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
6763 ERR("called but we don't have FreeType\n");
6767 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6770 ERR("called but we don't have FreeType\n");
6774 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6775 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6777 ERR("called but we don't have FreeType\n");
6781 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6782 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6784 ERR("called but we don't have FreeType\n");
6788 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6791 ERR("called but we don't have FreeType\n");
6795 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6797 ERR("called but we don't have FreeType\n");
6801 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6803 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6807 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6809 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6813 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6815 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
6819 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6821 FIXME("(%p, %p, %u): stub\n", font
, fs
, flags
);
6822 return DEFAULT_CHARSET
;
6825 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6830 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6832 FIXME("(%p, %p): stub\n", font
, glyphset
);
6836 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6841 /*************************************************************************
6842 * GetRasterizerCaps (GDI32.@)
6844 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6846 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6848 lprs
->nLanguageID
= 0;
6852 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6854 ERR("called but we don't have FreeType\n");
6858 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6860 ERR("called but we don't have FreeType\n");
6864 #endif /* HAVE_FREETYPE */