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 /*************************************************************
2751 * Initialize FreeType library and create a list of available faces
2753 BOOL
WineEngInit(void)
2755 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2756 static const WCHAR pathW
[] = {'P','a','t','h',0};
2758 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2759 WCHAR windowsdir
[MAX_PATH
];
2762 const char *data_dir
;
2766 /* update locale dependent font info in registry */
2769 if(!init_freetype()) return FALSE
;
2771 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2772 ERR("Failed to create font mutex\n");
2775 WaitForSingleObject(font_mutex
, INFINITE
);
2777 delete_external_font_keys();
2779 /* load the system bitmap fonts */
2780 load_system_fonts();
2782 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2783 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2784 strcatW(windowsdir
, fontsW
);
2785 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2787 ReadFontDir(unixname
, FALSE
);
2788 HeapFree(GetProcessHeap(), 0, unixname
);
2791 /* load the system truetype fonts */
2792 data_dir
= wine_get_data_dir();
2793 if (!data_dir
) data_dir
= wine_get_build_dir();
2794 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2795 strcpy(unixname
, data_dir
);
2796 strcat(unixname
, "/fonts/");
2797 ReadFontDir(unixname
, TRUE
);
2798 HeapFree(GetProcessHeap(), 0, unixname
);
2801 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2802 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2803 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2805 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2806 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2807 &hkey
) == ERROR_SUCCESS
) {
2808 LPWSTR data
, valueW
;
2809 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2810 &valuelen
, &datalen
, NULL
, NULL
);
2812 valuelen
++; /* returned value doesn't include room for '\0' */
2813 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2814 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2817 dlen
= datalen
* sizeof(WCHAR
);
2819 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
2820 &dlen
) == ERROR_SUCCESS
) {
2821 if(data
[0] && (data
[1] == ':'))
2823 if((unixname
= wine_get_unix_file_name(data
)))
2825 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2826 HeapFree(GetProcessHeap(), 0, unixname
);
2829 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
2831 WCHAR pathW
[MAX_PATH
];
2832 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2835 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2836 if((unixname
= wine_get_unix_file_name(pathW
)))
2838 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2839 HeapFree(GetProcessHeap(), 0, unixname
);
2842 load_font_from_data_dir(data
);
2844 /* reset dlen and vlen */
2849 HeapFree(GetProcessHeap(), 0, data
);
2850 HeapFree(GetProcessHeap(), 0, valueW
);
2854 load_fontconfig_fonts();
2856 /* then look in any directories that we've specified in the config file */
2857 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2858 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2864 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2866 len
+= sizeof(WCHAR
);
2867 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2868 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2870 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2871 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2872 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2873 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2877 LPSTR next
= strchr( ptr
, ':' );
2878 if (next
) *next
++ = 0;
2879 ReadFontDir( ptr
, TRUE
);
2882 HeapFree( GetProcessHeap(), 0, valueA
);
2884 HeapFree( GetProcessHeap(), 0, valueW
);
2893 update_reg_entries();
2895 update_system_links();
2896 init_system_links();
2898 ReleaseMutex(font_mutex
);
2903 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2906 TT_HoriHeader
*pHori
;
2910 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2911 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2913 if(height
== 0) height
= 16;
2915 /* Calc. height of EM square:
2917 * For +ve lfHeight we have
2918 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2919 * Re-arranging gives:
2920 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2922 * For -ve lfHeight we have
2924 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2925 * with il = winAscent + winDescent - units_per_em]
2930 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2931 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2932 pHori
->Ascender
- pHori
->Descender
);
2934 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2935 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2943 static struct font_mapping
*map_font_file( const char *name
)
2945 struct font_mapping
*mapping
;
2949 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2950 if (fstat( fd
, &st
) == -1) goto error
;
2952 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2954 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2956 mapping
->refcount
++;
2961 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2964 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2967 if (mapping
->data
== MAP_FAILED
)
2969 HeapFree( GetProcessHeap(), 0, mapping
);
2972 mapping
->refcount
= 1;
2973 mapping
->dev
= st
.st_dev
;
2974 mapping
->ino
= st
.st_ino
;
2975 mapping
->size
= st
.st_size
;
2976 list_add_tail( &mappings_list
, &mapping
->entry
);
2984 static void unmap_font_file( struct font_mapping
*mapping
)
2986 if (!--mapping
->refcount
)
2988 list_remove( &mapping
->entry
);
2989 munmap( mapping
->data
, mapping
->size
);
2990 HeapFree( GetProcessHeap(), 0, mapping
);
2994 static LONG
load_VDMX(GdiFont
*, LONG
);
2996 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3003 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3007 if (!(font
->mapping
= map_font_file( face
->file
)))
3009 WARN("failed to map %s\n", debugstr_a(face
->file
));
3012 data_ptr
= font
->mapping
->data
;
3013 data_size
= font
->mapping
->size
;
3017 data_ptr
= face
->font_data_ptr
;
3018 data_size
= face
->font_data_size
;
3021 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3023 ERR("FT_New_Face rets %d\n", err
);
3027 /* set it here, as load_VDMX needs it */
3028 font
->ft_face
= ft_face
;
3030 if(FT_IS_SCALABLE(ft_face
)) {
3031 /* load the VDMX table if we have one */
3032 font
->ppem
= load_VDMX(font
, height
);
3034 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3035 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3037 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3038 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3040 font
->ppem
= height
;
3041 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3042 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3048 static int get_nearest_charset(Face
*face
, int *cp
)
3050 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3051 a single face with the requested charset. The idea is to check if
3052 the selected font supports the current ANSI codepage, if it does
3053 return the corresponding charset, else return the first charset */
3056 int acp
= GetACP(), i
;
3060 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3061 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3062 return csi
.ciCharset
;
3064 for(i
= 0; i
< 32; i
++) {
3066 if(face
->fs
.fsCsb
[0] & fs0
) {
3067 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3069 return csi
.ciCharset
;
3072 FIXME("TCI failing on %x\n", fs0
);
3076 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3077 face
->fs
.fsCsb
[0], face
->file
);
3079 return DEFAULT_CHARSET
;
3082 static GdiFont
*alloc_font(void)
3084 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3086 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3087 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3089 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3090 ret
->total_kern_pairs
= (DWORD
)-1;
3091 ret
->kern_pairs
= NULL
;
3092 list_init(&ret
->hfontlist
);
3093 list_init(&ret
->child_fonts
);
3097 static void free_font(GdiFont
*font
)
3099 struct list
*cursor
, *cursor2
;
3102 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3104 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3105 list_remove(cursor
);
3107 free_font(child
->font
);
3108 HeapFree(GetProcessHeap(), 0, child
);
3111 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3113 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3114 DeleteObject(hfontlist
->hfont
);
3115 list_remove(&hfontlist
->entry
);
3116 HeapFree(GetProcessHeap(), 0, hfontlist
);
3119 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3120 if (font
->mapping
) unmap_font_file( font
->mapping
);
3121 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3122 HeapFree(GetProcessHeap(), 0, font
->potm
);
3123 HeapFree(GetProcessHeap(), 0, font
->name
);
3124 for (i
= 0; i
< font
->gmsize
; i
++)
3125 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3126 HeapFree(GetProcessHeap(), 0, font
->gm
);
3127 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3128 HeapFree(GetProcessHeap(), 0, font
);
3132 /*************************************************************
3135 * load the vdmx entry for the specified height
3138 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3139 ( ( (FT_ULong)_x4 << 24 ) | \
3140 ( (FT_ULong)_x3 << 16 ) | \
3141 ( (FT_ULong)_x2 << 8 ) | \
3144 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3159 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3163 BYTE devXRatio
, devYRatio
;
3164 USHORT numRecs
, numRatios
;
3165 DWORD result
, offset
= -1;
3169 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3171 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3174 /* FIXME: need the real device aspect ratio */
3178 numRecs
= GET_BE_WORD(hdr
[1]);
3179 numRatios
= GET_BE_WORD(hdr
[2]);
3181 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3182 for(i
= 0; i
< numRatios
; i
++) {
3185 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3186 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3189 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3191 if((ratio
.xRatio
== 0 &&
3192 ratio
.yStartRatio
== 0 &&
3193 ratio
.yEndRatio
== 0) ||
3194 (devXRatio
== ratio
.xRatio
&&
3195 devYRatio
>= ratio
.yStartRatio
&&
3196 devYRatio
<= ratio
.yEndRatio
))
3198 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3199 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3200 offset
= GET_BE_WORD(tmp
);
3206 FIXME("No suitable ratio found\n");
3210 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3212 BYTE startsz
, endsz
;
3215 recs
= GET_BE_WORD(group
.recs
);
3216 startsz
= group
.startsz
;
3217 endsz
= group
.endsz
;
3219 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3221 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3222 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3223 if(result
== GDI_ERROR
) {
3224 FIXME("Failed to retrieve vTable\n");
3229 for(i
= 0; i
< recs
; i
++) {
3230 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3231 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3232 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3234 if(yMax
+ -yMin
== height
) {
3237 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3240 if(yMax
+ -yMin
> height
) {
3243 goto end
; /* failed */
3245 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3246 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3247 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3248 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3254 TRACE("ppem not found for height %d\n", height
);
3258 HeapFree(GetProcessHeap(), 0, vTable
);
3264 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3266 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3267 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3268 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3269 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3270 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3273 static void calc_hash(FONT_DESC
*pfd
)
3275 DWORD hash
= 0, *ptr
, two_chars
;
3279 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3281 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3283 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3285 pwc
= (WCHAR
*)&two_chars
;
3287 *pwc
= toupperW(*pwc
);
3289 *pwc
= toupperW(*pwc
);
3293 hash
^= !pfd
->can_use_bitmap
;
3298 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3303 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3307 fd
.can_use_bitmap
= can_use_bitmap
;
3310 /* try the child list */
3311 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3312 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3313 if(!fontcmp(ret
, &fd
)) {
3314 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3315 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3316 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3317 if(hflist
->hfont
== hfont
)
3323 /* try the in-use list */
3324 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3325 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3326 if(!fontcmp(ret
, &fd
)) {
3327 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3328 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3329 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3330 if(hflist
->hfont
== hfont
)
3333 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3334 hflist
->hfont
= hfont
;
3335 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3340 /* then the unused list */
3341 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3342 while(font_elem_ptr
) {
3343 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3344 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3345 if(!fontcmp(ret
, &fd
)) {
3346 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3347 assert(list_empty(&ret
->hfontlist
));
3348 TRACE("Found %p in unused list\n", ret
);
3349 list_remove(&ret
->entry
);
3350 list_add_head(&gdi_font_list
, &ret
->entry
);
3351 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3352 hflist
->hfont
= hfont
;
3353 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3360 static void add_to_cache(GdiFont
*font
)
3362 static DWORD cache_num
= 1;
3364 font
->cache_num
= cache_num
++;
3365 list_add_head(&gdi_font_list
, &font
->entry
);
3368 /*************************************************************
3369 * create_child_font_list
3371 static BOOL
create_child_font_list(GdiFont
*font
)
3374 SYSTEM_LINKS
*font_link
;
3375 CHILD_FONT
*font_link_entry
, *new_child
;
3379 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3380 font_name
= psub
? psub
->to
.name
: font
->name
;
3381 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3383 if(!strcmpiW(font_link
->font_name
, font_name
))
3385 TRACE("found entry in system list\n");
3386 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3388 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3389 new_child
->face
= font_link_entry
->face
;
3390 new_child
->font
= NULL
;
3391 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3392 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3399 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3400 * Sans Serif. This is how asian windows get default fallbacks for fonts
3402 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3403 font
->charset
!= OEM_CHARSET
&&
3404 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3405 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3407 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3409 TRACE("found entry in default fallback list\n");
3410 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3412 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3413 new_child
->face
= font_link_entry
->face
;
3414 new_child
->font
= NULL
;
3415 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3416 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3426 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3428 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3430 if (pFT_Set_Charmap
)
3433 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3435 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3437 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3439 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3441 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3442 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3444 switch (ft_face
->charmaps
[i
]->platform_id
)
3447 cmap_def
= ft_face
->charmaps
[i
];
3449 case 0: /* Apple Unicode */
3450 cmap0
= ft_face
->charmaps
[i
];
3452 case 1: /* Macintosh */
3453 cmap1
= ft_face
->charmaps
[i
];
3456 cmap2
= ft_face
->charmaps
[i
];
3458 case 3: /* Microsoft */
3459 cmap3
= ft_face
->charmaps
[i
];
3464 if (cmap3
) /* prefer Microsoft cmap table */
3465 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3467 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3469 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3471 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3473 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3475 return ft_err
== FT_Err_Ok
;
3478 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3481 /*************************************************************
3482 * WineEngCreateFontInstance
3485 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3488 Face
*face
, *best
, *best_bitmap
;
3489 Family
*family
, *last_resort_family
;
3490 struct list
*family_elem_ptr
, *face_elem_ptr
;
3491 INT height
, width
= 0;
3492 unsigned int score
= 0, new_score
;
3493 signed int diff
= 0, newdiff
;
3494 BOOL bd
, it
, can_use_bitmap
;
3499 FontSubst
*psub
= NULL
;
3501 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3502 lf
.lfWidth
= abs(lf
.lfWidth
);
3504 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3506 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3507 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3508 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3511 if(dc
->GraphicsMode
== GM_ADVANCED
)
3512 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3515 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3516 font scaling abilities. */
3517 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3518 dcmat
.eM21
= dcmat
.eM12
= 0;
3521 /* Try to avoid not necessary glyph transformations */
3522 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3524 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3525 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3526 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3529 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3530 dcmat
.eM21
, dcmat
.eM22
);
3533 EnterCriticalSection( &freetype_cs
);
3535 /* check the cache first */
3536 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3537 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3538 LeaveCriticalSection( &freetype_cs
);
3542 TRACE("not in cache\n");
3543 if(list_empty(&font_list
)) /* No fonts installed */
3545 TRACE("No fonts installed\n");
3546 LeaveCriticalSection( &freetype_cs
);
3552 ret
->font_desc
.matrix
= dcmat
;
3553 ret
->font_desc
.lf
= lf
;
3554 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3555 calc_hash(&ret
->font_desc
);
3556 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3557 hflist
->hfont
= hfont
;
3558 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3560 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3561 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3562 original value lfCharSet. Note this is a special case for
3563 Symbol and doesn't happen at least for "Wingdings*" */
3565 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3566 lf
.lfCharSet
= SYMBOL_CHARSET
;
3568 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3569 switch(lf
.lfCharSet
) {
3570 case DEFAULT_CHARSET
:
3571 csi
.fs
.fsCsb
[0] = 0;
3574 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3575 csi
.fs
.fsCsb
[0] = 0;
3581 if(lf
.lfFaceName
[0] != '\0') {
3582 SYSTEM_LINKS
*font_link
;
3583 CHILD_FONT
*font_link_entry
;
3584 LPWSTR FaceName
= lf
.lfFaceName
;
3587 * Check for a leading '@' this signals that the font is being
3588 * requested in tategaki mode (vertical writing substitution) but
3589 * does not affect the fontface that is to be selected.
3591 if (lf
.lfFaceName
[0]=='@')
3592 FaceName
= &lf
.lfFaceName
[1];
3594 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3597 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3598 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3599 if (psub
->to
.charset
!= -1)
3600 lf
.lfCharSet
= psub
->to
.charset
;
3603 /* We want a match on name and charset or just name if
3604 charset was DEFAULT_CHARSET. If the latter then
3605 we fixup the returned charset later in get_nearest_charset
3606 where we'll either use the charset of the current ansi codepage
3607 or if that's unavailable the first charset that the font supports.
3609 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3610 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3611 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3612 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3614 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3615 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3616 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3617 if(face
->scalable
|| can_use_bitmap
)
3623 /* Search by full face name. */
3624 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3625 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3626 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3627 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3628 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
3629 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]))
3631 if(face
->scalable
|| can_use_bitmap
)
3638 * Try check the SystemLink list first for a replacement font.
3639 * We may find good replacements there.
3641 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3643 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3644 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3646 TRACE("found entry in system list\n");
3647 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3649 face
= font_link_entry
->face
;
3650 family
= face
->family
;
3651 if(csi
.fs
.fsCsb
[0] &
3652 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3654 if(face
->scalable
|| can_use_bitmap
)
3662 psub
= NULL
; /* substitution is no more relevant */
3664 /* If requested charset was DEFAULT_CHARSET then try using charset
3665 corresponding to the current ansi codepage */
3666 if (!csi
.fs
.fsCsb
[0])
3669 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3670 FIXME("TCI failed on codepage %d\n", acp
);
3671 csi
.fs
.fsCsb
[0] = 0;
3673 lf
.lfCharSet
= csi
.ciCharset
;
3676 /* Face families are in the top 4 bits of lfPitchAndFamily,
3677 so mask with 0xF0 before testing */
3679 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3680 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3681 strcpyW(lf
.lfFaceName
, defFixed
);
3682 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3683 strcpyW(lf
.lfFaceName
, defSerif
);
3684 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3685 strcpyW(lf
.lfFaceName
, defSans
);
3687 strcpyW(lf
.lfFaceName
, defSans
);
3688 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3689 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3690 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3691 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3692 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3693 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3694 if(face
->scalable
|| can_use_bitmap
)
3700 last_resort_family
= NULL
;
3701 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3702 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3703 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3704 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3705 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3708 if(can_use_bitmap
&& !last_resort_family
)
3709 last_resort_family
= family
;
3714 if(last_resort_family
) {
3715 family
= last_resort_family
;
3716 csi
.fs
.fsCsb
[0] = 0;
3720 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3721 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3722 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3723 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3724 if(face
->scalable
) {
3725 csi
.fs
.fsCsb
[0] = 0;
3726 WARN("just using first face for now\n");
3729 if(can_use_bitmap
&& !last_resort_family
)
3730 last_resort_family
= family
;
3733 if(!last_resort_family
) {
3734 FIXME("can't find a single appropriate font - bailing\n");
3736 LeaveCriticalSection( &freetype_cs
);
3740 WARN("could only find a bitmap font - this will probably look awful!\n");
3741 family
= last_resort_family
;
3742 csi
.fs
.fsCsb
[0] = 0;
3745 it
= lf
.lfItalic
? 1 : 0;
3746 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3748 height
= lf
.lfHeight
;
3750 face
= best
= best_bitmap
= NULL
;
3751 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3753 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3757 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3758 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3759 new_score
= (italic
^ it
) + (bold
^ bd
);
3760 if(!best
|| new_score
<= score
)
3762 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3763 italic
, bold
, it
, bd
);
3766 if(best
->scalable
&& score
== 0) break;
3770 newdiff
= height
- (signed int)(best
->size
.height
);
3772 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3773 if(!best_bitmap
|| new_score
< score
||
3774 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3776 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3779 if(score
== 0 && diff
== 0) break;
3786 face
= best
->scalable
? best
: best_bitmap
;
3787 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3788 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3791 height
= lf
.lfHeight
;
3795 if(csi
.fs
.fsCsb
[0]) {
3796 ret
->charset
= lf
.lfCharSet
;
3797 ret
->codepage
= csi
.ciACP
;
3800 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3802 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3803 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3805 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3807 if(!face
->scalable
) {
3808 /* Windows uses integer scaling factors for bitmap fonts */
3809 INT scale
, scaled_height
;
3810 GdiFont
*cachedfont
;
3812 /* FIXME: rotation of bitmap fonts is ignored */
3813 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3815 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3816 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3817 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3818 /* As we changed the matrix, we need to search the cache for the font again,
3819 * otherwise we might explode the cache. */
3820 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3821 TRACE("Found cached font after non-scalable matrix rescale!\n");
3823 LeaveCriticalSection( &freetype_cs
);
3826 calc_hash(&ret
->font_desc
);
3828 if (height
!= 0) height
= diff
;
3829 height
+= face
->size
.height
;
3831 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3832 scaled_height
= scale
* face
->size
.height
;
3833 /* Only jump to the next height if the difference <= 25% original height */
3834 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3835 /* The jump between unscaled and doubled is delayed by 1 */
3836 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3837 ret
->scale_y
= scale
;
3839 width
= face
->size
.x_ppem
>> 6;
3840 height
= face
->size
.y_ppem
>> 6;
3844 TRACE("font scale y: %f\n", ret
->scale_y
);
3846 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3851 LeaveCriticalSection( &freetype_cs
);
3855 ret
->ntmFlags
= face
->ntmFlags
;
3857 if (ret
->charset
== SYMBOL_CHARSET
&&
3858 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3861 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3865 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3868 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3869 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3870 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3871 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3872 create_child_font_list(ret
);
3874 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3876 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3877 if (length
!= GDI_ERROR
)
3879 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3880 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3881 TRACE("Loaded GSUB table of %i bytes\n",length
);
3885 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3888 LeaveCriticalSection( &freetype_cs
);
3892 static void dump_gdi_font_list(void)
3895 struct list
*elem_ptr
;
3897 TRACE("---------- gdiFont Cache ----------\n");
3898 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3899 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3900 TRACE("gdiFont=%p %s %d\n",
3901 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3904 TRACE("---------- Unused gdiFont Cache ----------\n");
3905 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3906 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3907 TRACE("gdiFont=%p %s %d\n",
3908 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3911 TRACE("---------- Child gdiFont Cache ----------\n");
3912 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
3913 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3914 TRACE("gdiFont=%p %s %d\n",
3915 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3919 /*************************************************************
3920 * WineEngDestroyFontInstance
3922 * free the gdiFont associated with this handle
3925 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3930 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3934 EnterCriticalSection( &freetype_cs
);
3936 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3938 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3939 while(hfontlist_elem_ptr
) {
3940 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3941 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3942 if(hflist
->hfont
== handle
) {
3943 TRACE("removing child font %p from child list\n", gdiFont
);
3944 list_remove(&gdiFont
->entry
);
3945 LeaveCriticalSection( &freetype_cs
);
3951 TRACE("destroying hfont=%p\n", handle
);
3953 dump_gdi_font_list();
3955 font_elem_ptr
= list_head(&gdi_font_list
);
3956 while(font_elem_ptr
) {
3957 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3958 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3960 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3961 while(hfontlist_elem_ptr
) {
3962 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3963 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3964 if(hflist
->hfont
== handle
) {
3965 list_remove(&hflist
->entry
);
3966 HeapFree(GetProcessHeap(), 0, hflist
);
3970 if(list_empty(&gdiFont
->hfontlist
)) {
3971 TRACE("Moving to Unused list\n");
3972 list_remove(&gdiFont
->entry
);
3973 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3978 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3979 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3980 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3981 while(font_elem_ptr
) {
3982 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3983 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3984 TRACE("freeing %p\n", gdiFont
);
3985 list_remove(&gdiFont
->entry
);
3988 LeaveCriticalSection( &freetype_cs
);
3992 /***************************************************
3993 * create_enum_charset_list
3995 * This function creates charset enumeration list because in DEFAULT_CHARSET
3996 * case, the ANSI codepage's charset takes precedence over other charsets.
3997 * This function works as a filter other than DEFAULT_CHARSET case.
3999 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4004 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4005 csi
.fs
.fsCsb
[0] != 0) {
4006 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4007 list
->element
[n
].charset
= csi
.ciCharset
;
4008 list
->element
[n
].name
= ElfScriptsW
[ffs(csi
.fs
.fsCsb
[0]) - 1];
4011 else { /* charset is DEFAULT_CHARSET or invalid. */
4014 /* Set the current codepage's charset as the first element. */
4016 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4017 csi
.fs
.fsCsb
[0] != 0) {
4018 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4019 list
->element
[n
].charset
= csi
.ciCharset
;
4020 list
->element
[n
].name
= ElfScriptsW
[ffs(csi
.fs
.fsCsb
[0]) - 1];
4024 /* Fill out left elements. */
4025 for (i
= 0; i
< 32; i
++) {
4027 fs
.fsCsb
[0] = 1L << i
;
4029 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4030 continue; /* skip, already added. */
4031 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4032 continue; /* skip, this is an invalid fsCsb bit. */
4034 list
->element
[n
].mask
= fs
.fsCsb
[0];
4035 list
->element
[n
].charset
= csi
.ciCharset
;
4036 list
->element
[n
].name
= ElfScriptsW
[i
];
4045 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4046 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4051 if (face
->cached_enum_data
)
4054 *pelf
= face
->cached_enum_data
->elf
;
4055 *pntm
= face
->cached_enum_data
->ntm
;
4056 *ptype
= face
->cached_enum_data
->type
;
4060 font
= alloc_font();
4062 if(face
->scalable
) {
4063 height
= -2048; /* 2048 is the most common em size */
4066 height
= face
->size
.y_ppem
>> 6;
4067 width
= face
->size
.x_ppem
>> 6;
4069 font
->scale_y
= 1.0;
4071 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4077 font
->name
= strdupW(face
->family
->FamilyName
);
4078 font
->ntmFlags
= face
->ntmFlags
;
4080 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4082 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4084 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4086 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4087 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4089 lstrcpynW(pelf
->elfFullName
,
4090 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4092 lstrcpynW(pelf
->elfStyle
,
4093 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4098 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4100 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4102 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4104 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4106 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4107 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4110 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4111 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4112 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4113 pntm
->ntmFontSig
= face
->fs
;
4115 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4117 pelf
->elfLogFont
.lfEscapement
= 0;
4118 pelf
->elfLogFont
.lfOrientation
= 0;
4119 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4120 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4121 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4122 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4123 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4124 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4125 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4126 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4127 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4128 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4129 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4132 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4133 *ptype
|= TRUETYPE_FONTTYPE
;
4134 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4135 *ptype
|= DEVICE_FONTTYPE
;
4136 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4137 *ptype
|= RASTER_FONTTYPE
;
4139 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4140 if (face
->cached_enum_data
)
4142 face
->cached_enum_data
->elf
= *pelf
;
4143 face
->cached_enum_data
->ntm
= *pntm
;
4144 face
->cached_enum_data
->type
= *ptype
;
4150 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4152 struct list
*face_elem_ptr
;
4154 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4156 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
)
4158 static const WCHAR spaceW
[] = { ' ',0 };
4159 WCHAR full_family_name
[LF_FULLFACESIZE
];
4160 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4162 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4164 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4165 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4169 strcpyW(full_family_name
, family
->FamilyName
);
4170 strcatW(full_family_name
, spaceW
);
4171 strcatW(full_family_name
, face
->StyleName
);
4172 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4178 static BOOL
face_matches(Face
*face
, const LOGFONTW
*lf
)
4180 static const WCHAR spaceW
[] = { ' ',0 };
4181 WCHAR full_family_name
[LF_FULLFACESIZE
];
4183 if (!strcmpiW(lf
->lfFaceName
, face
->family
->FamilyName
)) return TRUE
;
4185 if (strlenW(face
->family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4187 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4188 debugstr_w(face
->family
->FamilyName
), debugstr_w(face
->StyleName
));
4192 strcpyW(full_family_name
, face
->family
->FamilyName
);
4193 strcatW(full_family_name
, spaceW
);
4194 strcatW(full_family_name
, face
->StyleName
);
4195 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4198 static BOOL
enum_face_charsets(Face
*face
, struct enum_charset_list
*list
,
4199 FONTENUMPROCW proc
, LPARAM lparam
)
4202 NEWTEXTMETRICEXW ntm
;
4206 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4207 for(i
= 0; i
< list
->total
; i
++) {
4208 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4209 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4210 strcpyW(elf
.elfScript
, OEM_DOSW
);
4211 i
= 32; /* break out of loop */
4212 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4215 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4216 if(list
->element
[i
].name
)
4217 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4219 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4221 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4222 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4223 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4224 list
->element
[i
].charset
, type
, debugstr_w(elf
.elfScript
),
4225 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4226 ntm
.ntmTm
.ntmFlags
);
4227 /* release section before callback (FIXME) */
4228 LeaveCriticalSection( &freetype_cs
);
4229 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4230 EnterCriticalSection( &freetype_cs
);
4235 /*************************************************************
4239 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4243 struct list
*family_elem_ptr
, *face_elem_ptr
;
4245 struct enum_charset_list enum_charsets
;
4249 lf
.lfCharSet
= DEFAULT_CHARSET
;
4250 lf
.lfPitchAndFamily
= 0;
4251 lf
.lfFaceName
[0] = 0;
4255 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4257 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4260 EnterCriticalSection( &freetype_cs
);
4261 if(plf
->lfFaceName
[0]) {
4263 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4266 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4267 debugstr_w(psub
->to
.name
));
4269 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4273 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4274 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4275 if(family_matches(family
, plf
)) {
4276 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4277 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4278 if (!face_matches(face
, plf
)) continue;
4279 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return 0;
4284 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4285 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4286 face_elem_ptr
= list_head(&family
->faces
);
4287 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4288 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return 0;
4291 LeaveCriticalSection( &freetype_cs
);
4295 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4297 pt
->x
.value
= vec
->x
>> 6;
4298 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4299 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4300 pt
->y
.value
= vec
->y
>> 6;
4301 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4302 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4306 /***************************************************
4307 * According to the MSDN documentation on WideCharToMultiByte,
4308 * certain codepages cannot set the default_used parameter.
4309 * This returns TRUE if the codepage can set that parameter, false else
4310 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4312 static BOOL
codepage_sets_default_used(UINT codepage
)
4326 * GSUB Table handling functions
4329 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4331 const GSUB_CoverageFormat1
* cf1
;
4335 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4337 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4339 TRACE("Coverage Format 1, %i glyphs\n",count
);
4340 for (i
= 0; i
< count
; i
++)
4341 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4345 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4347 const GSUB_CoverageFormat2
* cf2
;
4350 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4352 count
= GET_BE_WORD(cf2
->RangeCount
);
4353 TRACE("Coverage Format 2, %i ranges\n",count
);
4354 for (i
= 0; i
< count
; i
++)
4356 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4358 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4359 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4361 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4362 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4368 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4373 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4375 const GSUB_ScriptList
*script
;
4376 const GSUB_Script
*deflt
= NULL
;
4378 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4380 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4381 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4383 const GSUB_Script
*scr
;
4386 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4387 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4389 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4391 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4397 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4401 const GSUB_LangSys
*Lang
;
4403 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4405 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4407 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4408 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4410 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4413 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4416 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4422 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4425 const GSUB_FeatureList
*feature
;
4426 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4428 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4429 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4431 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4432 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4434 const GSUB_Feature
*feat
;
4435 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4442 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4446 const GSUB_LookupList
*lookup
;
4447 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4449 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4450 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4452 const GSUB_LookupTable
*look
;
4453 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4454 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4455 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4456 if (GET_BE_WORD(look
->LookupType
) != 1)
4457 FIXME("We only handle SubType 1\n");
4462 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4464 const GSUB_SingleSubstFormat1
*ssf1
;
4465 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4466 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4467 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4469 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4470 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4471 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4473 TRACE(" Glyph 0x%x ->",glyph
);
4474 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4475 TRACE(" 0x%x\n",glyph
);
4480 const GSUB_SingleSubstFormat2
*ssf2
;
4484 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4485 offset
= GET_BE_WORD(ssf1
->Coverage
);
4486 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4487 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4488 TRACE(" Coverage index %i\n",index
);
4491 TRACE(" Glyph is 0x%x ->",glyph
);
4492 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4493 TRACE("0x%x\n",glyph
);
4502 static const char* get_opentype_script(const GdiFont
*font
)
4505 * I am not sure if this is the correct way to generate our script tag
4508 switch (font
->charset
)
4510 case ANSI_CHARSET
: return "latn";
4511 case BALTIC_CHARSET
: return "latn"; /* ?? */
4512 case CHINESEBIG5_CHARSET
: return "hani";
4513 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4514 case GB2312_CHARSET
: return "hani";
4515 case GREEK_CHARSET
: return "grek";
4516 case HANGUL_CHARSET
: return "hang";
4517 case RUSSIAN_CHARSET
: return "cyrl";
4518 case SHIFTJIS_CHARSET
: return "kana";
4519 case TURKISH_CHARSET
: return "latn"; /* ?? */
4520 case VIETNAMESE_CHARSET
: return "latn";
4521 case JOHAB_CHARSET
: return "latn"; /* ?? */
4522 case ARABIC_CHARSET
: return "arab";
4523 case HEBREW_CHARSET
: return "hebr";
4524 case THAI_CHARSET
: return "thai";
4525 default: return "latn";
4529 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4531 const GSUB_Header
*header
;
4532 const GSUB_Script
*script
;
4533 const GSUB_LangSys
*language
;
4534 const GSUB_Feature
*feature
;
4536 if (!font
->GSUB_Table
)
4539 header
= font
->GSUB_Table
;
4541 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4544 TRACE("Script not found\n");
4547 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4550 TRACE("Language not found\n");
4553 feature
= GSUB_get_feature(header
, language
, "vrt2");
4555 feature
= GSUB_get_feature(header
, language
, "vert");
4558 TRACE("vrt2/vert feature not found\n");
4561 return GSUB_apply_feature(header
, feature
, glyph
);
4564 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4568 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4569 WCHAR wc
= (WCHAR
)glyph
;
4571 BOOL
*default_used_pointer
;
4574 default_used_pointer
= NULL
;
4575 default_used
= FALSE
;
4576 if (codepage_sets_default_used(font
->codepage
))
4577 default_used_pointer
= &default_used
;
4578 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4581 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4582 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4583 return get_GSUB_vert_glyph(font
,ret
);
4586 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
4588 if (glyph
< 0x100) glyph
+= 0xf000;
4589 /* there is a number of old pre-Unicode "broken" TTFs, which
4590 do have symbols at U+00XX instead of U+f0XX */
4591 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
4592 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
4594 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4596 return get_GSUB_vert_glyph(font
,glyphId
);
4599 /*************************************************************
4600 * WineEngGetGlyphIndices
4603 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4604 LPWORD pgi
, DWORD flags
)
4608 BOOL got_default
= FALSE
;
4610 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
4612 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4616 for(i
= 0; i
< count
; i
++)
4618 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4623 if (FT_IS_SFNT(font
->ft_face
))
4625 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4626 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4631 WineEngGetTextMetrics(font
, &textm
);
4632 default_char
= textm
.tmDefaultChar
;
4636 pgi
[i
] = default_char
;
4642 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4644 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4645 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4648 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4650 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4651 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4654 /*************************************************************
4655 * WineEngGetGlyphOutline
4657 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4658 * except that the first parameter is the HWINEENGFONT of the font in
4659 * question rather than an HDC.
4662 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4663 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4666 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4667 FT_Face ft_face
= incoming_font
->ft_face
;
4668 GdiFont
*font
= incoming_font
;
4669 FT_UInt glyph_index
;
4670 DWORD width
, height
, pitch
, needed
= 0;
4671 FT_Bitmap ft_bitmap
;
4673 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4675 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4676 double widthRatio
= 1.0;
4677 FT_Matrix transMat
= identityMat
;
4678 FT_Matrix transMatUnrotated
;
4679 BOOL needsTransform
= FALSE
;
4680 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4681 UINT original_index
;
4683 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4684 buflen
, buf
, lpmat
);
4686 TRACE("font transform %f %f %f %f\n",
4687 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4688 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4691 EnterCriticalSection( &freetype_cs
);
4693 if(format
& GGO_GLYPH_INDEX
) {
4694 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4695 original_index
= glyph
;
4696 format
&= ~GGO_GLYPH_INDEX
;
4698 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4699 ft_face
= font
->ft_face
;
4700 original_index
= glyph_index
;
4703 if(format
& GGO_UNHINTED
) {
4704 load_flags
|= FT_LOAD_NO_HINTING
;
4705 format
&= ~GGO_UNHINTED
;
4708 /* tategaki never appears to happen to lower glyph index */
4709 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4712 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4713 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4714 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4715 font
->gmsize
* sizeof(GM
*));
4717 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4718 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
4720 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4721 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4722 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4723 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4724 LeaveCriticalSection( &freetype_cs
);
4725 return 1; /* FIXME */
4729 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4730 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4732 /* Scaling factor */
4737 WineEngGetTextMetrics(font
, &tm
);
4739 widthRatio
= (double)font
->aveWidth
;
4740 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4743 widthRatio
= font
->scale_y
;
4745 /* Scaling transform */
4746 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4749 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4752 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4754 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4755 needsTransform
= TRUE
;
4758 /* Slant transform */
4759 if (font
->fake_italic
) {
4762 slantMat
.xx
= (1 << 16);
4763 slantMat
.xy
= ((1 << 16) >> 2);
4765 slantMat
.yy
= (1 << 16);
4766 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4767 needsTransform
= TRUE
;
4770 /* Rotation transform */
4771 transMatUnrotated
= transMat
;
4772 if(font
->orientation
&& !tategaki
) {
4773 FT_Matrix rotationMat
;
4775 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4776 pFT_Vector_Unit(&vecAngle
, angle
);
4777 rotationMat
.xx
= vecAngle
.x
;
4778 rotationMat
.xy
= -vecAngle
.y
;
4779 rotationMat
.yx
= -rotationMat
.xy
;
4780 rotationMat
.yy
= rotationMat
.xx
;
4782 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4783 needsTransform
= TRUE
;
4786 /* World transform */
4787 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4790 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4791 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4792 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4793 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4794 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4795 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4796 needsTransform
= TRUE
;
4799 /* Extra transformation specified by caller */
4800 if (!is_identity_MAT2(lpmat
))
4803 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4804 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
4805 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
4806 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4807 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4808 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4809 needsTransform
= TRUE
;
4812 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4813 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4814 format
== GGO_GRAY8_BITMAP
))
4816 load_flags
|= FT_LOAD_NO_BITMAP
;
4819 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4822 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4823 LeaveCriticalSection( &freetype_cs
);
4827 if(!needsTransform
) {
4828 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4829 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4830 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
4832 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4833 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4834 ft_face
->glyph
->metrics
.height
) & -64;
4835 lpgm
->gmCellIncX
= adv
;
4836 lpgm
->gmCellIncY
= 0;
4843 for(xc
= 0; xc
< 2; xc
++) {
4844 for(yc
= 0; yc
< 2; yc
++) {
4845 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4846 xc
* ft_face
->glyph
->metrics
.width
);
4847 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4848 yc
* ft_face
->glyph
->metrics
.height
;
4849 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4850 pFT_Vector_Transform(&vec
, &transMat
);
4851 if(xc
== 0 && yc
== 0) {
4852 left
= right
= vec
.x
;
4853 top
= bottom
= vec
.y
;
4855 if(vec
.x
< left
) left
= vec
.x
;
4856 else if(vec
.x
> right
) right
= vec
.x
;
4857 if(vec
.y
< bottom
) bottom
= vec
.y
;
4858 else if(vec
.y
> top
) top
= vec
.y
;
4863 right
= (right
+ 63) & -64;
4864 bottom
= bottom
& -64;
4865 top
= (top
+ 63) & -64;
4867 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4868 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4870 pFT_Vector_Transform(&vec
, &transMat
);
4871 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4872 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4874 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4876 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4877 adv
= (vec
.x
+63) >> 6;
4881 bbx
= (right
- left
) >> 6;
4882 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4883 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4884 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4885 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4887 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4888 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4889 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4891 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4892 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
4894 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4895 FONT_GM(font
,original_index
)->adv
= adv
;
4896 FONT_GM(font
,original_index
)->lsb
= lsb
;
4897 FONT_GM(font
,original_index
)->bbx
= bbx
;
4898 FONT_GM(font
,original_index
)->init
= TRUE
;
4901 if(format
== GGO_METRICS
)
4903 LeaveCriticalSection( &freetype_cs
);
4904 return 1; /* FIXME */
4907 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
4908 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4909 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4910 format
== GGO_GRAY8_BITMAP
))
4912 TRACE("loaded a bitmap\n");
4913 LeaveCriticalSection( &freetype_cs
);
4919 width
= lpgm
->gmBlackBoxX
;
4920 height
= lpgm
->gmBlackBoxY
;
4921 pitch
= ((width
+ 31) >> 5) << 2;
4922 needed
= pitch
* height
;
4924 if(!buf
|| !buflen
) break;
4926 switch(ft_face
->glyph
->format
) {
4927 case ft_glyph_format_bitmap
:
4929 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4930 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4931 INT h
= ft_face
->glyph
->bitmap
.rows
;
4933 memcpy(dst
, src
, w
);
4934 src
+= ft_face
->glyph
->bitmap
.pitch
;
4940 case ft_glyph_format_outline
:
4941 ft_bitmap
.width
= width
;
4942 ft_bitmap
.rows
= height
;
4943 ft_bitmap
.pitch
= pitch
;
4944 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4945 ft_bitmap
.buffer
= buf
;
4948 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4950 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4952 /* Note: FreeType will only set 'black' bits for us. */
4953 memset(buf
, 0, needed
);
4954 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4958 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4959 LeaveCriticalSection( &freetype_cs
);
4964 case GGO_GRAY2_BITMAP
:
4965 case GGO_GRAY4_BITMAP
:
4966 case GGO_GRAY8_BITMAP
:
4967 case WINE_GGO_GRAY16_BITMAP
:
4969 unsigned int mult
, row
, col
;
4972 width
= lpgm
->gmBlackBoxX
;
4973 height
= lpgm
->gmBlackBoxY
;
4974 pitch
= (width
+ 3) / 4 * 4;
4975 needed
= pitch
* height
;
4977 if(!buf
|| !buflen
) break;
4979 switch(ft_face
->glyph
->format
) {
4980 case ft_glyph_format_bitmap
:
4982 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4983 INT h
= ft_face
->glyph
->bitmap
.rows
;
4985 memset( buf
, 0, needed
);
4987 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
4988 if (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) dst
[x
] = 0xff;
4989 src
+= ft_face
->glyph
->bitmap
.pitch
;
4992 LeaveCriticalSection( &freetype_cs
);
4995 case ft_glyph_format_outline
:
4997 ft_bitmap
.width
= width
;
4998 ft_bitmap
.rows
= height
;
4999 ft_bitmap
.pitch
= pitch
;
5000 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5001 ft_bitmap
.buffer
= buf
;
5004 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5006 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5008 memset(ft_bitmap
.buffer
, 0, buflen
);
5010 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5012 if(format
== GGO_GRAY2_BITMAP
)
5014 else if(format
== GGO_GRAY4_BITMAP
)
5016 else if(format
== GGO_GRAY8_BITMAP
)
5018 else /* format == WINE_GGO_GRAY16_BITMAP */
5020 LeaveCriticalSection( &freetype_cs
);
5026 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5027 LeaveCriticalSection( &freetype_cs
);
5032 for(row
= 0; row
< height
; row
++) {
5034 for(col
= 0; col
< width
; col
++, ptr
++) {
5035 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
5042 case WINE_GGO_HRGB_BITMAP
:
5043 case WINE_GGO_HBGR_BITMAP
:
5044 case WINE_GGO_VRGB_BITMAP
:
5045 case WINE_GGO_VBGR_BITMAP
:
5046 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5048 switch (ft_face
->glyph
->format
)
5050 case FT_GLYPH_FORMAT_BITMAP
:
5055 width
= lpgm
->gmBlackBoxX
;
5056 height
= lpgm
->gmBlackBoxY
;
5058 needed
= pitch
* height
;
5060 if (!buf
|| !buflen
) break;
5062 memset(buf
, 0, buflen
);
5064 src
= ft_face
->glyph
->bitmap
.buffer
;
5065 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5067 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5070 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5072 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
5073 ((unsigned int *)dst
)[x
] = ~0u;
5082 case FT_GLYPH_FORMAT_OUTLINE
:
5086 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5087 INT x_shift
, y_shift
;
5089 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5090 FT_Render_Mode render_mode
=
5091 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5092 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5094 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5096 if ( render_mode
== FT_RENDER_MODE_LCD
)
5098 lpgm
->gmBlackBoxX
+= 2;
5099 lpgm
->gmptGlyphOrigin
.x
-= 1;
5103 lpgm
->gmBlackBoxY
+= 2;
5104 lpgm
->gmptGlyphOrigin
.y
+= 1;
5108 width
= lpgm
->gmBlackBoxX
;
5109 height
= lpgm
->gmBlackBoxY
;
5111 needed
= pitch
* height
;
5113 if (!buf
|| !buflen
) break;
5115 memset(buf
, 0, buflen
);
5117 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5119 if ( needsTransform
)
5120 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5122 if ( pFT_Library_SetLcdFilter
)
5123 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5124 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5126 src
= ft_face
->glyph
->bitmap
.buffer
;
5127 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5128 src_width
= ft_face
->glyph
->bitmap
.width
;
5129 src_height
= ft_face
->glyph
->bitmap
.rows
;
5131 if ( render_mode
== FT_RENDER_MODE_LCD
)
5139 rgb_interval
= src_pitch
;
5144 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5145 if ( x_shift
< 0 ) x_shift
= 0;
5146 if ( x_shift
+ (src_width
/ hmul
) > width
)
5147 x_shift
= width
- (src_width
/ hmul
);
5149 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5150 if ( y_shift
< 0 ) y_shift
= 0;
5151 if ( y_shift
+ (src_height
/ vmul
) > height
)
5152 y_shift
= height
- (src_height
/ vmul
);
5154 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5155 while ( src_height
)
5157 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5161 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5162 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5163 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5164 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5168 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5169 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5170 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5171 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5174 src
+= src_pitch
* vmul
;
5183 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5184 LeaveCriticalSection ( &freetype_cs
);
5191 LeaveCriticalSection( &freetype_cs
);
5197 int contour
, point
= 0, first_pt
;
5198 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5199 TTPOLYGONHEADER
*pph
;
5201 DWORD pph_start
, cpfx
, type
;
5203 if(buflen
== 0) buf
= NULL
;
5205 if (needsTransform
&& buf
) {
5206 pFT_Outline_Transform(outline
, &transMat
);
5209 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5211 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5214 pph
->dwType
= TT_POLYGON_TYPE
;
5215 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5217 needed
+= sizeof(*pph
);
5219 while(point
<= outline
->contours
[contour
]) {
5220 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5221 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5222 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5226 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5229 } while(point
<= outline
->contours
[contour
] &&
5230 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5231 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5232 /* At the end of a contour Windows adds the start point, but
5234 if(point
> outline
->contours
[contour
] &&
5235 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5237 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5239 } else if(point
<= outline
->contours
[contour
] &&
5240 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5241 /* add closing pt for bezier */
5243 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5251 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5254 pph
->cb
= needed
- pph_start
;
5260 /* Convert the quadratic Beziers to cubic Beziers.
5261 The parametric eqn for a cubic Bezier is, from PLRM:
5262 r(t) = at^3 + bt^2 + ct + r0
5263 with the control points:
5268 A quadratic Bezier has the form:
5269 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5271 So equating powers of t leads to:
5272 r1 = 2/3 p1 + 1/3 p0
5273 r2 = 2/3 p1 + 1/3 p2
5274 and of course r0 = p0, r3 = p2
5277 int contour
, point
= 0, first_pt
;
5278 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5279 TTPOLYGONHEADER
*pph
;
5281 DWORD pph_start
, cpfx
, type
;
5282 FT_Vector cubic_control
[4];
5283 if(buflen
== 0) buf
= NULL
;
5285 if (needsTransform
&& buf
) {
5286 pFT_Outline_Transform(outline
, &transMat
);
5289 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5291 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5294 pph
->dwType
= TT_POLYGON_TYPE
;
5295 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5297 needed
+= sizeof(*pph
);
5299 while(point
<= outline
->contours
[contour
]) {
5300 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5301 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5302 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5305 if(type
== TT_PRIM_LINE
) {
5307 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5311 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5314 /* FIXME: Possible optimization in endpoint calculation
5315 if there are two consecutive curves */
5316 cubic_control
[0] = outline
->points
[point
-1];
5317 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5318 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5319 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5320 cubic_control
[0].x
>>= 1;
5321 cubic_control
[0].y
>>= 1;
5323 if(point
+1 > outline
->contours
[contour
])
5324 cubic_control
[3] = outline
->points
[first_pt
];
5326 cubic_control
[3] = outline
->points
[point
+1];
5327 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5328 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5329 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5330 cubic_control
[3].x
>>= 1;
5331 cubic_control
[3].y
>>= 1;
5334 /* r1 = 1/3 p0 + 2/3 p1
5335 r2 = 1/3 p2 + 2/3 p1 */
5336 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5337 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5338 cubic_control
[2] = cubic_control
[1];
5339 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5340 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5341 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5342 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5344 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5345 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5346 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5351 } while(point
<= outline
->contours
[contour
] &&
5352 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5353 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5354 /* At the end of a contour Windows adds the start point,
5355 but only for Beziers and we've already done that.
5357 if(point
<= outline
->contours
[contour
] &&
5358 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5359 /* This is the closing pt of a bezier, but we've already
5360 added it, so just inc point and carry on */
5367 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5370 pph
->cb
= needed
- pph_start
;
5376 FIXME("Unsupported format %d\n", format
);
5377 LeaveCriticalSection( &freetype_cs
);
5380 LeaveCriticalSection( &freetype_cs
);
5384 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5386 FT_Face ft_face
= font
->ft_face
;
5387 #ifdef HAVE_FREETYPE_FTWINFNT_H
5388 FT_WinFNT_HeaderRec winfnt_header
;
5390 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5391 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5392 font
->potm
->otmSize
= size
;
5394 #define TM font->potm->otmTextMetrics
5395 #ifdef HAVE_FREETYPE_FTWINFNT_H
5396 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5398 TM
.tmHeight
= winfnt_header
.pixel_height
;
5399 TM
.tmAscent
= winfnt_header
.ascent
;
5400 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5401 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5402 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5403 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5404 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5405 TM
.tmWeight
= winfnt_header
.weight
;
5407 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5408 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5409 TM
.tmFirstChar
= winfnt_header
.first_char
;
5410 TM
.tmLastChar
= winfnt_header
.last_char
;
5411 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5412 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5413 TM
.tmItalic
= winfnt_header
.italic
;
5414 TM
.tmUnderlined
= font
->underline
;
5415 TM
.tmStruckOut
= font
->strikeout
;
5416 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5417 TM
.tmCharSet
= winfnt_header
.charset
;
5422 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5423 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5424 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5425 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5426 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5427 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5428 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5429 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5431 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5432 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5434 TM
.tmLastChar
= 255;
5435 TM
.tmDefaultChar
= 32;
5436 TM
.tmBreakChar
= 32;
5437 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5438 TM
.tmUnderlined
= font
->underline
;
5439 TM
.tmStruckOut
= font
->strikeout
;
5440 /* NB inverted meaning of TMPF_FIXED_PITCH */
5441 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5442 TM
.tmCharSet
= font
->charset
;
5450 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5452 double scale_x
, scale_y
;
5456 scale_x
= (double)font
->aveWidth
;
5457 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5460 scale_x
= font
->scale_y
;
5462 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5463 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5465 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5466 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5468 SCALE_Y(ptm
->tmHeight
);
5469 SCALE_Y(ptm
->tmAscent
);
5470 SCALE_Y(ptm
->tmDescent
);
5471 SCALE_Y(ptm
->tmInternalLeading
);
5472 SCALE_Y(ptm
->tmExternalLeading
);
5473 SCALE_Y(ptm
->tmOverhang
);
5475 SCALE_X(ptm
->tmAveCharWidth
);
5476 SCALE_X(ptm
->tmMaxCharWidth
);
5482 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5484 double scale_x
, scale_y
;
5488 scale_x
= (double)font
->aveWidth
;
5489 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5492 scale_x
= font
->scale_y
;
5494 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5495 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5497 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5499 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5500 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5502 SCALE_Y(potm
->otmAscent
);
5503 SCALE_Y(potm
->otmDescent
);
5504 SCALE_Y(potm
->otmLineGap
);
5505 SCALE_Y(potm
->otmsCapEmHeight
);
5506 SCALE_Y(potm
->otmsXHeight
);
5507 SCALE_Y(potm
->otmrcFontBox
.top
);
5508 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5509 SCALE_X(potm
->otmrcFontBox
.left
);
5510 SCALE_X(potm
->otmrcFontBox
.right
);
5511 SCALE_Y(potm
->otmMacAscent
);
5512 SCALE_Y(potm
->otmMacDescent
);
5513 SCALE_Y(potm
->otmMacLineGap
);
5514 SCALE_X(potm
->otmptSubscriptSize
.x
);
5515 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5516 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5517 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5518 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5519 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5520 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5521 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5522 SCALE_Y(potm
->otmsStrikeoutSize
);
5523 SCALE_Y(potm
->otmsStrikeoutPosition
);
5524 SCALE_Y(potm
->otmsUnderscoreSize
);
5525 SCALE_Y(potm
->otmsUnderscorePosition
);
5531 /*************************************************************
5532 * WineEngGetTextMetrics
5535 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5538 EnterCriticalSection( &freetype_cs
);
5540 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5541 if(!get_bitmap_text_metrics(font
))
5543 LeaveCriticalSection( &freetype_cs
);
5547 /* Make sure that the font has sane width/height ratio */
5550 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
5552 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
5558 *ptm
= font
->potm
->otmTextMetrics
;
5559 scale_font_metrics(font
, ptm
);
5560 LeaveCriticalSection( &freetype_cs
);
5564 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5568 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5570 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
5576 /*************************************************************
5577 * WineEngGetOutlineTextMetrics
5580 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5581 OUTLINETEXTMETRICW
*potm
)
5583 FT_Face ft_face
= font
->ft_face
;
5584 UINT needed
, lenfam
, lensty
, ret
;
5586 TT_HoriHeader
*pHori
;
5587 TT_Postscript
*pPost
;
5588 FT_Fixed x_scale
, y_scale
;
5589 WCHAR
*family_nameW
, *style_nameW
;
5590 static const WCHAR spaceW
[] = {' ', '\0'};
5592 INT ascent
, descent
;
5594 TRACE("font=%p\n", font
);
5596 if(!FT_IS_SCALABLE(ft_face
))
5600 EnterCriticalSection( &freetype_cs
);
5603 if(cbSize
>= font
->potm
->otmSize
)
5605 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5606 scale_outline_font_metrics(font
, potm
);
5608 LeaveCriticalSection( &freetype_cs
);
5609 return font
->potm
->otmSize
;
5613 needed
= sizeof(*potm
);
5615 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5616 family_nameW
= strdupW(font
->name
);
5618 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5620 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5621 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5622 style_nameW
, lensty
/sizeof(WCHAR
));
5624 /* These names should be read from the TT name table */
5626 /* length of otmpFamilyName */
5629 /* length of otmpFaceName */
5630 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5631 needed
+= lenfam
; /* just the family name */
5633 needed
+= lenfam
+ lensty
; /* family + " " + style */
5636 /* length of otmpStyleName */
5639 /* length of otmpFullName */
5640 needed
+= lenfam
+ lensty
;
5643 x_scale
= ft_face
->size
->metrics
.x_scale
;
5644 y_scale
= ft_face
->size
->metrics
.y_scale
;
5646 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5648 FIXME("Can't find OS/2 table - not TT font?\n");
5653 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5655 FIXME("Can't find HHEA table - not TT font?\n");
5660 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5662 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",
5663 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5664 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5665 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5666 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5667 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5669 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5670 font
->potm
->otmSize
= needed
;
5672 #define TM font->potm->otmTextMetrics
5674 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5675 ascent
= pHori
->Ascender
;
5676 descent
= -pHori
->Descender
;
5678 ascent
= pOS2
->usWinAscent
;
5679 descent
= pOS2
->usWinDescent
;
5683 TM
.tmAscent
= font
->yMax
;
5684 TM
.tmDescent
= -font
->yMin
;
5685 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5687 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5688 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5689 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5690 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5693 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5696 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5698 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5699 ((ascent
+ descent
) -
5700 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5702 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5703 if (TM
.tmAveCharWidth
== 0) {
5704 TM
.tmAveCharWidth
= 1;
5706 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5707 TM
.tmWeight
= FW_REGULAR
;
5708 if (font
->fake_bold
)
5709 TM
.tmWeight
= FW_BOLD
;
5712 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
5714 if (pOS2
->usWeightClass
> FW_MEDIUM
)
5715 TM
.tmWeight
= pOS2
->usWeightClass
;
5717 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
5718 TM
.tmWeight
= pOS2
->usWeightClass
;
5721 TM
.tmDigitizedAspectX
= 300;
5722 TM
.tmDigitizedAspectY
= 300;
5723 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5724 * symbol range to 0 - f0ff
5727 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
5732 case 1257: /* Baltic */
5733 TM
.tmLastChar
= 0xf8fd;
5736 TM
.tmLastChar
= 0xf0ff;
5738 TM
.tmBreakChar
= 0x20;
5739 TM
.tmDefaultChar
= 0x1f;
5743 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
5744 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
5746 if(pOS2
->usFirstCharIndex
<= 1)
5747 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
5748 else if (pOS2
->usFirstCharIndex
> 0xff)
5749 TM
.tmBreakChar
= 0x20;
5751 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
5752 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
5754 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5755 TM
.tmUnderlined
= font
->underline
;
5756 TM
.tmStruckOut
= font
->strikeout
;
5758 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5759 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5760 (pOS2
->version
== 0xFFFFU
||
5761 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5762 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5764 TM
.tmPitchAndFamily
= 0;
5766 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
5768 case PAN_FAMILY_SCRIPT
:
5769 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5772 case PAN_FAMILY_DECORATIVE
:
5773 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5778 case PAN_FAMILY_TEXT_DISPLAY
:
5779 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
5780 /* which is clearly not what the panose spec says. */
5782 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
5783 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
5784 TM
.tmPitchAndFamily
= FF_MODERN
;
5787 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
5792 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5795 case PAN_SERIF_COVE
:
5796 case PAN_SERIF_OBTUSE_COVE
:
5797 case PAN_SERIF_SQUARE_COVE
:
5798 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
5799 case PAN_SERIF_SQUARE
:
5800 case PAN_SERIF_THIN
:
5801 case PAN_SERIF_BONE
:
5802 case PAN_SERIF_EXAGGERATED
:
5803 case PAN_SERIF_TRIANGLE
:
5804 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5807 case PAN_SERIF_NORMAL_SANS
:
5808 case PAN_SERIF_OBTUSE_SANS
:
5809 case PAN_SERIF_PERP_SANS
:
5810 case PAN_SERIF_FLARED
:
5811 case PAN_SERIF_ROUNDED
:
5812 TM
.tmPitchAndFamily
|= FF_SWISS
;
5819 if(FT_IS_SCALABLE(ft_face
))
5820 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5822 if(FT_IS_SFNT(ft_face
))
5824 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5825 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5827 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5830 TM
.tmCharSet
= font
->charset
;
5832 font
->potm
->otmFiller
= 0;
5833 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5834 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5835 font
->potm
->otmfsType
= pOS2
->fsType
;
5836 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5837 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5838 font
->potm
->otmItalicAngle
= 0; /* POST table */
5839 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5840 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5841 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5842 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5843 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5844 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5845 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5846 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5847 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5848 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5849 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5850 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5851 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5852 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5853 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5854 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5855 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5856 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5857 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5858 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5859 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5860 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5861 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5862 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5864 font
->potm
->otmsUnderscoreSize
= 0;
5865 font
->potm
->otmsUnderscorePosition
= 0;
5867 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5868 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5872 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5873 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5874 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5875 strcpyW((WCHAR
*)cp
, family_nameW
);
5877 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5878 strcpyW((WCHAR
*)cp
, style_nameW
);
5880 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5881 strcpyW((WCHAR
*)cp
, family_nameW
);
5882 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5883 strcatW((WCHAR
*)cp
, spaceW
);
5884 strcatW((WCHAR
*)cp
, style_nameW
);
5885 cp
+= lenfam
+ lensty
;
5888 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5889 strcpyW((WCHAR
*)cp
, family_nameW
);
5890 strcatW((WCHAR
*)cp
, spaceW
);
5891 strcatW((WCHAR
*)cp
, style_nameW
);
5894 if(potm
&& needed
<= cbSize
)
5896 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5897 scale_outline_font_metrics(font
, potm
);
5901 HeapFree(GetProcessHeap(), 0, style_nameW
);
5902 HeapFree(GetProcessHeap(), 0, family_nameW
);
5904 LeaveCriticalSection( &freetype_cs
);
5908 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5910 HFONTLIST
*hfontlist
;
5911 child
->font
= alloc_font();
5912 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5913 if(!child
->font
->ft_face
)
5915 free_font(child
->font
);
5920 child
->font
->font_desc
= font
->font_desc
;
5921 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5922 child
->font
->orientation
= font
->orientation
;
5923 child
->font
->scale_y
= font
->scale_y
;
5924 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5925 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5926 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
5927 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5928 child
->font
->base_font
= font
;
5929 list_add_head(&child_font_list
, &child
->font
->entry
);
5930 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5934 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5937 CHILD_FONT
*child_font
;
5940 font
= font
->base_font
;
5942 *linked_font
= font
;
5944 if((*glyph
= get_glyph_index(font
, c
)))
5947 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5949 if(!child_font
->font
)
5950 if(!load_child_font(font
, child_font
))
5953 if(!child_font
->font
->ft_face
)
5955 g
= get_glyph_index(child_font
->font
, c
);
5959 *linked_font
= child_font
->font
;
5966 /*************************************************************
5967 * WineEngGetCharWidth
5970 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5973 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5976 FT_UInt glyph_index
;
5977 GdiFont
*linked_font
;
5979 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5982 EnterCriticalSection( &freetype_cs
);
5983 for(c
= firstChar
; c
<= lastChar
; c
++) {
5984 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5985 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5986 &gm
, 0, NULL
, &identity
);
5987 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5989 LeaveCriticalSection( &freetype_cs
);
5993 /*************************************************************
5994 * WineEngGetCharABCWidths
5997 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6000 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6003 FT_UInt glyph_index
;
6004 GdiFont
*linked_font
;
6006 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
6008 if(!FT_IS_SCALABLE(font
->ft_face
))
6012 EnterCriticalSection( &freetype_cs
);
6014 for(c
= firstChar
; c
<= lastChar
; c
++) {
6015 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
6016 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6017 &gm
, 0, NULL
, &identity
);
6018 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6019 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6020 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6021 FONT_GM(linked_font
,glyph_index
)->bbx
;
6023 LeaveCriticalSection( &freetype_cs
);
6027 /*************************************************************
6028 * WineEngGetCharABCWidthsFloat
6031 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
6033 static const MAT2 identity
= {{0,1}, {0,0}, {0,0}, {0,1}};
6036 FT_UInt glyph_index
;
6037 GdiFont
*linked_font
;
6039 TRACE("%p, %d, %d, %p\n", font
, first
, last
, buffer
);
6042 EnterCriticalSection( &freetype_cs
);
6044 for (c
= first
; c
<= last
; c
++)
6046 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
6047 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6048 &gm
, 0, NULL
, &identity
);
6049 buffer
[c
- first
].abcfA
= FONT_GM(linked_font
, glyph_index
)->lsb
;
6050 buffer
[c
- first
].abcfB
= FONT_GM(linked_font
, glyph_index
)->bbx
;
6051 buffer
[c
- first
].abcfC
= FONT_GM(linked_font
, glyph_index
)->adv
-
6052 FONT_GM(linked_font
, glyph_index
)->lsb
-
6053 FONT_GM(linked_font
, glyph_index
)->bbx
;
6055 LeaveCriticalSection( &freetype_cs
);
6059 /*************************************************************
6060 * WineEngGetCharABCWidthsI
6063 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6066 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6069 FT_UInt glyph_index
;
6070 GdiFont
*linked_font
;
6072 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
6076 EnterCriticalSection( &freetype_cs
);
6078 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
6080 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6081 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6082 &gm
, 0, NULL
, &identity
);
6083 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6084 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6085 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6086 - FONT_GM(linked_font
,c
)->bbx
;
6089 for(c
= 0; c
< count
; c
++) {
6090 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6091 &gm
, 0, NULL
, &identity
);
6092 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6093 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6094 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6095 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6098 LeaveCriticalSection( &freetype_cs
);
6102 /*************************************************************
6103 * WineEngGetTextExtentExPoint
6106 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6107 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6109 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6114 FT_UInt glyph_index
;
6115 GdiFont
*linked_font
;
6117 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
6121 EnterCriticalSection( &freetype_cs
);
6124 WineEngGetTextMetrics(font
, &tm
);
6125 size
->cy
= tm
.tmHeight
;
6127 for(idx
= 0; idx
< count
; idx
++) {
6128 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
6129 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6130 &gm
, 0, NULL
, &identity
);
6131 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6133 if (! pnfit
|| ext
<= max_ext
) {
6143 LeaveCriticalSection( &freetype_cs
);
6144 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6148 /*************************************************************
6149 * WineEngGetTextExtentExPointI
6152 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6153 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6155 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6161 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
6164 EnterCriticalSection( &freetype_cs
);
6167 WineEngGetTextMetrics(font
, &tm
);
6168 size
->cy
= tm
.tmHeight
;
6170 for(idx
= 0; idx
< count
; idx
++) {
6171 WineEngGetGlyphOutline(font
, indices
[idx
],
6172 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
6174 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
6176 if (! pnfit
|| ext
<= max_ext
) {
6186 LeaveCriticalSection( &freetype_cs
);
6187 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6191 /*************************************************************
6192 * WineEngGetFontData
6195 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6198 FT_Face ft_face
= font
->ft_face
;
6202 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6203 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6204 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6206 if(!FT_IS_SFNT(ft_face
))
6214 if(table
) { /* MS tags differ in endianness from FT ones */
6215 table
= table
>> 24 | table
<< 24 |
6216 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
6219 /* make sure value of len is the value freetype says it needs */
6222 FT_ULong needed
= 0;
6223 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
6224 if( !err
&& needed
< len
) len
= needed
;
6226 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
6229 TRACE("Can't find table %c%c%c%c\n",
6230 /* bytes were reversed */
6231 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
6232 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
6238 /*************************************************************
6239 * WineEngGetTextFace
6242 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6244 INT n
= strlenW(font
->name
) + 1;
6246 lstrcpynW(str
, font
->name
, count
);
6247 return min(count
, n
);
6252 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6254 if (fs
) *fs
= font
->fs
;
6255 return font
->charset
;
6258 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6260 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6261 struct list
*first_hfont
;
6265 EnterCriticalSection( &freetype_cs
);
6266 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6267 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6268 if(font
== linked_font
)
6269 *new_hfont
= dc
->hFont
;
6272 first_hfont
= list_head(&linked_font
->hfontlist
);
6273 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6275 LeaveCriticalSection( &freetype_cs
);
6279 /* Retrieve a list of supported Unicode ranges for a given font.
6280 * Can be called with NULL gs to calculate the buffer size. Returns
6281 * the number of ranges found.
6283 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6285 DWORD num_ranges
= 0;
6287 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6290 FT_ULong char_code
, char_code_prev
;
6293 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6295 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6296 face
->num_glyphs
, glyph_code
, char_code
);
6298 if (!glyph_code
) return 0;
6302 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6303 gs
->ranges
[0].cGlyphs
= 0;
6304 gs
->cGlyphsSupported
= 0;
6310 if (char_code
< char_code_prev
)
6312 ERR("expected increasing char code from FT_Get_Next_Char\n");
6315 if (char_code
- char_code_prev
> 1)
6320 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6321 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6322 gs
->cGlyphsSupported
++;
6327 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6328 gs
->cGlyphsSupported
++;
6330 char_code_prev
= char_code
;
6331 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6335 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6340 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6343 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
6345 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6348 glyphset
->cbThis
= size
;
6349 glyphset
->cRanges
= num_ranges
;
6350 glyphset
->flAccel
= 0;
6355 /*************************************************************
6358 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6362 EnterCriticalSection( &freetype_cs
);
6363 ret
= !list_empty(&font
->child_fonts
);
6364 LeaveCriticalSection( &freetype_cs
);
6368 static BOOL
is_hinting_enabled(void)
6370 /* Use the >= 2.2.0 function if available */
6371 if(pFT_Get_TrueType_Engine_Type
)
6373 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6374 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6376 #ifdef FT_DRIVER_HAS_HINTER
6381 /* otherwise if we've been compiled with < 2.2.0 headers
6382 use the internal macro */
6383 mod
= pFT_Get_Module(library
, "truetype");
6384 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6392 static BOOL
is_subpixel_rendering_enabled( void )
6394 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6395 return pFT_Library_SetLcdFilter
&&
6396 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6402 /*************************************************************************
6403 * GetRasterizerCaps (GDI32.@)
6405 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6407 static int hinting
= -1;
6408 static int subpixel
= -1;
6412 hinting
= is_hinting_enabled();
6413 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6416 if ( subpixel
== -1 )
6418 subpixel
= is_subpixel_rendering_enabled();
6419 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6422 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6423 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6425 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6426 lprs
->nLanguageID
= 0;
6430 /*************************************************************
6431 * WineEngRealizationInfo
6433 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6435 FIXME("(%p, %p): stub!\n", font
, info
);
6438 if(FT_IS_SCALABLE(font
->ft_face
))
6441 info
->cache_num
= font
->cache_num
;
6442 info
->unknown2
= -1;
6446 /*************************************************************************
6447 * Kerning support for TrueType fonts
6449 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6451 struct TT_kern_table
6457 struct TT_kern_subtable
6466 USHORT horizontal
: 1;
6468 USHORT cross_stream
: 1;
6469 USHORT override
: 1;
6470 USHORT reserved1
: 4;
6476 struct TT_format0_kern_subtable
6480 USHORT entrySelector
;
6491 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6492 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6493 const USHORT
*glyph_to_char
,
6494 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6497 const struct TT_kern_pair
*tt_kern_pair
;
6499 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6501 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6503 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6504 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6505 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6507 if (!kern_pair
|| !cPairs
)
6510 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6512 nPairs
= min(nPairs
, cPairs
);
6514 for (i
= 0; i
< nPairs
; i
++)
6516 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6517 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6518 /* this algorithm appears to better match what Windows does */
6519 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6520 if (kern_pair
->iKernAmount
< 0)
6522 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6523 kern_pair
->iKernAmount
-= font
->ppem
;
6525 else if (kern_pair
->iKernAmount
> 0)
6527 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6528 kern_pair
->iKernAmount
+= font
->ppem
;
6530 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6532 TRACE("left %u right %u value %d\n",
6533 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6537 TRACE("copied %u entries\n", nPairs
);
6541 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6545 const struct TT_kern_table
*tt_kern_table
;
6546 const struct TT_kern_subtable
*tt_kern_subtable
;
6548 USHORT
*glyph_to_char
;
6551 EnterCriticalSection( &freetype_cs
);
6552 if (font
->total_kern_pairs
!= (DWORD
)-1)
6554 if (cPairs
&& kern_pair
)
6556 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6557 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6558 LeaveCriticalSection( &freetype_cs
);
6561 LeaveCriticalSection( &freetype_cs
);
6562 return font
->total_kern_pairs
;
6565 font
->total_kern_pairs
= 0;
6567 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6569 if (length
== GDI_ERROR
)
6571 TRACE("no kerning data in the font\n");
6572 LeaveCriticalSection( &freetype_cs
);
6576 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6579 WARN("Out of memory\n");
6580 LeaveCriticalSection( &freetype_cs
);
6584 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6586 /* build a glyph index to char code map */
6587 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6590 WARN("Out of memory allocating a glyph index to char code map\n");
6591 HeapFree(GetProcessHeap(), 0, buf
);
6592 LeaveCriticalSection( &freetype_cs
);
6596 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6602 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6604 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6605 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6609 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6611 /* FIXME: This doesn't match what Windows does: it does some fancy
6612 * things with duplicate glyph index to char code mappings, while
6613 * we just avoid overriding existing entries.
6615 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6616 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6618 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6625 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6626 for (n
= 0; n
<= 65535; n
++)
6627 glyph_to_char
[n
] = (USHORT
)n
;
6630 tt_kern_table
= buf
;
6631 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6632 TRACE("version %u, nTables %u\n",
6633 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6635 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6637 for (i
= 0; i
< nTables
; i
++)
6639 struct TT_kern_subtable tt_kern_subtable_copy
;
6641 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6642 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6643 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6645 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6646 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6647 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6649 /* According to the TrueType specification this is the only format
6650 * that will be properly interpreted by Windows and OS/2
6652 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6654 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6656 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6657 glyph_to_char
, NULL
, 0);
6658 font
->total_kern_pairs
+= new_chunk
;
6660 if (!font
->kern_pairs
)
6661 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6662 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6664 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6665 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6667 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6668 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6671 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6673 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6676 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6677 HeapFree(GetProcessHeap(), 0, buf
);
6679 if (cPairs
&& kern_pair
)
6681 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6682 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6683 LeaveCriticalSection( &freetype_cs
);
6686 LeaveCriticalSection( &freetype_cs
);
6687 return font
->total_kern_pairs
;
6690 #else /* HAVE_FREETYPE */
6692 /*************************************************************************/
6694 BOOL
WineEngInit(void)
6698 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6702 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6707 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6712 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6713 LPWORD pgi
, DWORD flags
)
6718 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6719 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6722 ERR("called but we don't have FreeType\n");
6726 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6728 ERR("called but we don't have FreeType\n");
6732 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6733 OUTLINETEXTMETRICW
*potm
)
6735 ERR("called but we don't have FreeType\n");
6739 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6742 ERR("called but we don't have FreeType\n");
6746 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6749 ERR("called but we don't have FreeType\n");
6753 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
6755 ERR("called but we don't have FreeType\n");
6759 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6762 ERR("called but we don't have FreeType\n");
6766 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6767 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6769 ERR("called but we don't have FreeType\n");
6773 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6774 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6776 ERR("called but we don't have FreeType\n");
6780 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6783 ERR("called but we don't have FreeType\n");
6787 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6789 ERR("called but we don't have FreeType\n");
6793 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6795 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6799 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6801 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6805 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6807 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
6811 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6813 FIXME("(%p, %p, %u): stub\n", font
, fs
, flags
);
6814 return DEFAULT_CHARSET
;
6817 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6822 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6824 FIXME("(%p, %p): stub\n", font
, glyphset
);
6828 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6833 /*************************************************************************
6834 * GetRasterizerCaps (GDI32.@)
6836 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6838 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6840 lprs
->nLanguageID
= 0;
6844 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6846 ERR("called but we don't have FreeType\n");
6850 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6852 ERR("called but we don't have FreeType\n");
6856 #endif /* HAVE_FREETYPE */