2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(font
);
96 #ifdef HAVE_FT2BUILD_H
99 #ifdef HAVE_FREETYPE_FREETYPE_H
100 #include <freetype/freetype.h>
102 #ifdef HAVE_FREETYPE_FTGLYPH_H
103 #include <freetype/ftglyph.h>
105 #ifdef HAVE_FREETYPE_TTTABLES_H
106 #include <freetype/tttables.h>
108 #ifdef HAVE_FREETYPE_FTTYPES_H
109 #include <freetype/fttypes.h>
111 #ifdef HAVE_FREETYPE_FTSNAMES_H
112 #include <freetype/ftsnames.h>
114 #ifdef HAVE_FREETYPE_TTNAMEID_H
115 #include <freetype/ttnameid.h>
117 #ifdef HAVE_FREETYPE_FTOUTLN_H
118 #include <freetype/ftoutln.h>
120 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
121 #include <freetype/internal/sfnt.h>
123 #ifdef HAVE_FREETYPE_FTTRIGON_H
124 #include <freetype/fttrigon.h>
126 #ifdef HAVE_FREETYPE_FTWINFNT_H
127 #include <freetype/ftwinfnt.h>
129 #ifdef HAVE_FREETYPE_FTMODAPI_H
130 #include <freetype/ftmodapi.h>
132 #ifdef HAVE_FREETYPE_FTLCDFIL_H
133 #include <freetype/ftlcdfil.h>
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
139 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType
;
145 static FT_Library library
= 0;
152 static FT_Version_t FT_Version
;
153 static DWORD FT_SimpleVersion
;
155 static void *ft_handle
= NULL
;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit
);
159 MAKE_FUNCPTR(FT_Done_Face
);
160 MAKE_FUNCPTR(FT_Get_Char_Index
);
161 MAKE_FUNCPTR(FT_Get_Module
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
165 MAKE_FUNCPTR(FT_Init_FreeType
);
166 MAKE_FUNCPTR(FT_Load_Glyph
);
167 MAKE_FUNCPTR(FT_Matrix_Multiply
);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
171 MAKE_FUNCPTR(FT_MulFix
);
173 MAKE_FUNCPTR(FT_New_Face
);
174 MAKE_FUNCPTR(FT_New_Memory_Face
);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
176 MAKE_FUNCPTR(FT_Outline_Transform
);
177 MAKE_FUNCPTR(FT_Outline_Translate
);
178 MAKE_FUNCPTR(FT_Select_Charmap
);
179 MAKE_FUNCPTR(FT_Set_Charmap
);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
181 MAKE_FUNCPTR(FT_Vector_Transform
);
182 MAKE_FUNCPTR(FT_Render_Glyph
);
183 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
184 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
185 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
186 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
191 #ifdef HAVE_FREETYPE_FTWINFNT_H
192 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
195 #ifdef SONAME_LIBFONTCONFIG
196 #include <fontconfig/fontconfig.h>
197 MAKE_FUNCPTR(FcConfigGetCurrent
);
198 MAKE_FUNCPTR(FcFontList
);
199 MAKE_FUNCPTR(FcFontSetDestroy
);
200 MAKE_FUNCPTR(FcInit
);
201 MAKE_FUNCPTR(FcObjectSetAdd
);
202 MAKE_FUNCPTR(FcObjectSetCreate
);
203 MAKE_FUNCPTR(FcObjectSetDestroy
);
204 MAKE_FUNCPTR(FcPatternCreate
);
205 MAKE_FUNCPTR(FcPatternDestroy
);
206 MAKE_FUNCPTR(FcPatternGetBool
);
207 MAKE_FUNCPTR(FcPatternGetString
);
213 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
214 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
215 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
218 #ifndef ft_encoding_none
219 #define FT_ENCODING_NONE ft_encoding_none
221 #ifndef ft_encoding_ms_symbol
222 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
224 #ifndef ft_encoding_unicode
225 #define FT_ENCODING_UNICODE ft_encoding_unicode
227 #ifndef ft_encoding_apple_roman
228 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
231 #ifdef WORDS_BIGENDIAN
232 #define GET_BE_WORD(x) (x)
234 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
237 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
244 FT_Short internal_leading
;
247 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
248 So to let this compile on older versions of FreeType we'll define the
249 new structure here. */
251 FT_Short height
, width
;
252 FT_Pos size
, x_ppem
, y_ppem
;
258 NEWTEXTMETRICEXW ntm
;
262 typedef struct tagFace
{
267 DWORD font_data_size
;
270 FONTSIGNATURE fs_links
;
272 FT_Fixed font_version
;
274 Bitmap_Size size
; /* set if face is a bitmap */
275 BOOL external
; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily
*family
;
277 /* Cached data for Enum */
278 struct enum_data
*cached_enum_data
;
281 typedef struct tagFamily
{
283 const WCHAR
*FamilyName
;
289 INT adv
; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST
{
322 struct list hfontlist
;
323 OUTLINETEXTMETRICW
*potm
;
324 DWORD total_kern_pairs
;
325 KERNINGPAIR
*kern_pairs
;
326 struct list child_fonts
;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping
*mapping
;
353 const WCHAR
*font_name
;
357 #define GM_BLOCK_SIZE 128
358 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
360 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
361 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
362 #define UNUSED_CACHE_SIZE 10
363 static struct list child_font_list
= LIST_INIT(child_font_list
);
364 static struct list system_links
= LIST_INIT(system_links
);
366 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
368 static struct list font_list
= LIST_INIT(font_list
);
370 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
371 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
372 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
374 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
375 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
376 'W','i','n','d','o','w','s','\\',
377 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
378 'F','o','n','t','s','\0'};
380 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
381 'W','i','n','d','o','w','s',' ','N','T','\\',
382 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
383 'F','o','n','t','s','\0'};
385 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
386 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
387 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
388 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
390 static const WCHAR
* const SystemFontValues
[4] = {
397 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
398 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
400 /* Interesting and well-known (frequently-assumed!) font names */
401 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
402 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 };
403 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
404 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
405 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
406 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
407 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
408 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
410 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
411 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
412 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
413 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
414 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
415 'E','u','r','o','p','e','a','n','\0'};
416 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
417 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
418 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
419 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
420 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
421 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
422 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
423 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
424 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
425 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
426 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
427 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
429 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
439 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
447 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
456 typedef struct tagFontSubst
{
472 static struct list mappings_list
= LIST_INIT( mappings_list
);
474 static CRITICAL_SECTION freetype_cs
;
475 static CRITICAL_SECTION_DEBUG critsect_debug
=
478 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
479 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
481 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
483 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
485 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
486 static BOOL use_default_fallback
= FALSE
;
488 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
490 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
491 'W','i','n','d','o','w','s',' ','N','T','\\',
492 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
493 'S','y','s','t','e','m','L','i','n','k',0};
495 /****************************************
496 * Notes on .fon files
498 * The fonts System, FixedSys and Terminal are special. There are typically multiple
499 * versions installed for different resolutions and codepages. Windows stores which one to use
500 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
502 * FIXEDFON.FON FixedSys
504 * OEMFONT.FON Terminal
505 * LogPixels Current dpi set by the display control panel applet
506 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
507 * also has a LogPixels value that appears to mirror this)
509 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
510 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
511 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
512 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
513 * so that makes sense.
515 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
516 * to be mapped into the registry on Windows 2000 at least).
519 * ega80woa.fon=ega80850.fon
520 * ega40woa.fon=ega40850.fon
521 * cga80woa.fon=cga80850.fon
522 * cga40woa.fon=cga40850.fon
525 /* These are all structures needed for the GSUB table */
527 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
528 #define TATEGAKI_LOWER_BOUND 0x02F1
544 GSUB_ScriptRecord ScriptRecord
[1];
550 } GSUB_LangSysRecord
;
555 GSUB_LangSysRecord LangSysRecord
[1];
559 WORD LookupOrder
; /* Reserved */
560 WORD ReqFeatureIndex
;
562 WORD FeatureIndex
[1];
568 } GSUB_FeatureRecord
;
572 GSUB_FeatureRecord FeatureRecord
[1];
576 WORD FeatureParams
; /* Reserved */
578 WORD LookupListIndex
[1];
597 } GSUB_CoverageFormat1
;
602 WORD StartCoverageIndex
;
608 GSUB_RangeRecord RangeRecord
[1];
609 } GSUB_CoverageFormat2
;
612 WORD SubstFormat
; /* = 1 */
615 } GSUB_SingleSubstFormat1
;
618 WORD SubstFormat
; /* = 2 */
622 }GSUB_SingleSubstFormat2
;
624 #ifdef HAVE_CARBON_CARBON_H
625 static char *find_cache_dir(void)
629 static char cached_path
[MAX_PATH
];
630 static const char *wine
= "/Wine", *fonts
= "/Fonts";
632 if(*cached_path
) return cached_path
;
634 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
637 WARN("can't create cached data folder\n");
640 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
643 WARN("can't create cached data path\n");
647 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
649 ERR("Could not create full path\n");
653 strcat(cached_path
, wine
);
655 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
657 WARN("Couldn't mkdir %s\n", cached_path
);
661 strcat(cached_path
, fonts
);
662 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
664 WARN("Couldn't mkdir %s\n", cached_path
);
671 /******************************************************************
674 * Extracts individual TrueType font files from a Mac suitcase font
675 * and saves them into the user's caches directory (see
677 * Returns a NULL terminated array of filenames.
679 * We do this because they are apps that try to read ttf files
680 * themselves and they don't like Mac suitcase files.
682 static char **expand_mac_font(const char *path
)
689 const char *filename
;
693 unsigned int size
, max_size
;
696 TRACE("path %s\n", path
);
698 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
701 WARN("failed to get ref\n");
705 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
708 TRACE("no data fork, so trying resource fork\n");
709 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
712 TRACE("unable to open resource fork\n");
719 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
722 CloseResFile(res_ref
);
726 out_dir
= find_cache_dir();
728 filename
= strrchr(path
, '/');
729 if(!filename
) filename
= path
;
732 /* output filename has the form out_dir/filename_%04x.ttf */
733 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
740 unsigned short *num_faces_ptr
, num_faces
, face
;
743 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
745 fond
= Get1IndResource(fond_res
, idx
);
747 TRACE("got fond resource %d\n", idx
);
750 fam_rec
= *(FamRec
**)fond
;
751 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
752 num_faces
= GET_BE_WORD(*num_faces_ptr
);
754 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
755 TRACE("num faces %04x\n", num_faces
);
756 for(face
= 0; face
< num_faces
; face
++, assoc
++)
759 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
760 unsigned short size
, font_id
;
763 size
= GET_BE_WORD(assoc
->fontSize
);
764 font_id
= GET_BE_WORD(assoc
->fontID
);
767 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
771 TRACE("trying to load sfnt id %04x\n", font_id
);
772 sfnt
= GetResource(sfnt_res
, font_id
);
775 TRACE("can't get sfnt resource %04x\n", font_id
);
779 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
784 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
786 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
787 if(fd
!= -1 || errno
== EEXIST
)
791 unsigned char *sfnt_data
;
794 sfnt_data
= *(unsigned char**)sfnt
;
795 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
799 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
802 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
804 ret
.array
[ret
.size
++] = output
;
808 WARN("unable to create %s\n", output
);
809 HeapFree(GetProcessHeap(), 0, output
);
812 ReleaseResource(sfnt
);
815 ReleaseResource(fond
);
818 CloseResFile(res_ref
);
823 #endif /* HAVE_CARBON_CARBON_H */
825 static inline BOOL
is_win9x(void)
827 return GetVersion() & 0x80000000;
830 This function builds an FT_Fixed from a double. It fails if the absolute
831 value of the float number is greater than 32768.
833 static inline FT_Fixed
FT_FixedFromFloat(double f
)
839 This function builds an FT_Fixed from a FIXED. It simply put f.value
840 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
842 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
844 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
848 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
853 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
854 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
856 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
857 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
859 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
861 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
863 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
867 file
= strrchr(face
->file
, '/');
872 if(!strcasecmp(file
, file_nameA
))
874 HeapFree(GetProcessHeap(), 0, file_nameA
);
879 HeapFree(GetProcessHeap(), 0, file_nameA
);
883 static Family
*find_family_from_name(const WCHAR
*name
)
887 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
889 if(!strcmpiW(family
->FamilyName
, name
))
896 static void DumpSubstList(void)
900 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
902 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
903 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
904 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
906 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
907 debugstr_w(psub
->to
.name
));
912 static LPWSTR
strdupW(LPCWSTR p
)
915 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
916 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
921 static LPSTR
strdupA(LPCSTR p
)
924 DWORD len
= (strlen(p
) + 1);
925 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
930 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
935 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
937 if(!strcmpiW(element
->from
.name
, from_name
) &&
938 (element
->from
.charset
== from_charset
||
939 element
->from
.charset
== -1))
946 #define ADD_FONT_SUBST_FORCE 1
948 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
950 FontSubst
*from_exist
, *to_exist
;
952 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
954 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
956 list_remove(&from_exist
->entry
);
957 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
958 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
959 HeapFree(GetProcessHeap(), 0, from_exist
);
965 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
969 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
970 subst
->to
.name
= strdupW(to_exist
->to
.name
);
973 list_add_tail(subst_list
, &subst
->entry
);
978 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
979 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
980 HeapFree(GetProcessHeap(), 0, subst
);
984 static void split_subst_info(NameCs
*nc
, LPSTR str
)
986 CHAR
*p
= strrchr(str
, ',');
991 nc
->charset
= strtol(p
+1, NULL
, 10);
994 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
995 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
996 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
999 static void LoadSubstList(void)
1003 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1007 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1008 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1009 &hkey
) == ERROR_SUCCESS
) {
1011 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1012 &valuelen
, &datalen
, NULL
, NULL
);
1014 valuelen
++; /* returned value doesn't include room for '\0' */
1015 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1016 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1020 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1021 &dlen
) == ERROR_SUCCESS
) {
1022 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1024 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1025 split_subst_info(&psub
->from
, value
);
1026 split_subst_info(&psub
->to
, data
);
1028 /* Win 2000 doesn't allow mapping between different charsets
1029 or mapping of DEFAULT_CHARSET */
1030 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1031 psub
->to
.charset
== DEFAULT_CHARSET
) {
1032 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1033 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1034 HeapFree(GetProcessHeap(), 0, psub
);
1036 add_font_subst(&font_subst_list
, psub
, 0);
1038 /* reset dlen and vlen */
1042 HeapFree(GetProcessHeap(), 0, data
);
1043 HeapFree(GetProcessHeap(), 0, value
);
1049 /*****************************************************************
1050 * get_name_table_entry
1052 * Supply the platform, encoding, language and name ids in req
1053 * and if the name exists the function will fill in the string
1054 * and string_len members. The string is owned by FreeType so
1055 * don't free it. Returns TRUE if the name is found else FALSE.
1057 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1060 FT_UInt num_names
, name_index
;
1062 if(FT_IS_SFNT(ft_face
))
1064 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1066 for(name_index
= 0; name_index
< num_names
; name_index
++)
1068 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1070 if((name
.platform_id
== req
->platform_id
) &&
1071 (name
.encoding_id
== req
->encoding_id
) &&
1072 (name
.language_id
== req
->language_id
) &&
1073 (name
.name_id
== req
->name_id
))
1075 req
->string
= name
.string
;
1076 req
->string_len
= name
.string_len
;
1083 req
->string_len
= 0;
1087 static WCHAR
*get_familyname(FT_Face ft_face
)
1089 WCHAR
*family
= NULL
;
1092 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1093 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1094 name
.language_id
= GetUserDefaultLCID();
1095 name
.name_id
= TT_NAME_ID_FONT_FAMILY
;
1097 if(get_name_table_entry(ft_face
, &name
))
1101 /* String is not nul terminated and string_len is a byte length. */
1102 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1103 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1105 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1106 family
[i
] = GET_BE_WORD(*tmp
);
1109 TRACE("Got localised name %s\n", debugstr_w(family
));
1116 /*****************************************************************
1119 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1120 * of FreeType that don't export this function.
1123 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1128 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1129 if(pFT_Load_Sfnt_Table
)
1131 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1133 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1134 else /* Do it the hard way */
1136 TT_Face tt_face
= (TT_Face
) ft_face
;
1137 SFNT_Interface
*sfnt
;
1138 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1141 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1145 /* A field was added in the middle of the structure in 2.1.x */
1146 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1148 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1156 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1157 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1158 "Please upgrade your freetype library.\n");
1161 err
= FT_Err_Unimplemented_Feature
;
1167 static inline int TestStyles(DWORD flags
, DWORD styles
)
1169 return (flags
& styles
) == styles
;
1172 static int StyleOrdering(Face
*face
)
1174 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1176 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1178 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1180 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1183 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1184 debugstr_w(face
->family
->FamilyName
),
1185 debugstr_w(face
->StyleName
),
1191 /* Add a style of face to a font family using an ordering of the list such
1192 that regular fonts come before bold and italic, and single styles come
1193 before compound styles. */
1194 static void AddFaceToFamily(Face
*face
, Family
*family
)
1198 LIST_FOR_EACH( entry
, &family
->faces
)
1200 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1201 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1203 list_add_before( entry
, &face
->entry
);
1206 #define ADDFONT_EXTERNAL_FONT 0x01
1207 #define ADDFONT_FORCE_BITMAP 0x02
1208 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1212 TT_Header
*pHeader
= NULL
;
1213 WCHAR
*english_family
, *localised_family
, *StyleW
;
1217 struct list
*family_elem_ptr
, *face_elem_ptr
;
1219 FT_Long face_index
= 0, num_faces
;
1220 #ifdef HAVE_FREETYPE_FTWINFNT_H
1221 FT_WinFNT_HeaderRec winfnt_header
;
1223 int i
, bitmap_num
, internal_leading
;
1226 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1227 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1229 #ifdef HAVE_CARBON_CARBON_H
1230 if(file
&& !fake_family
)
1232 char **mac_list
= expand_mac_font(file
);
1235 BOOL had_one
= FALSE
;
1237 for(cursor
= mac_list
; *cursor
; cursor
++)
1240 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1241 HeapFree(GetProcessHeap(), 0, *cursor
);
1243 HeapFree(GetProcessHeap(), 0, mac_list
);
1248 #endif /* HAVE_CARBON_CARBON_H */
1251 char *family_name
= fake_family
;
1255 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1256 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1259 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1260 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1264 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1268 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*/
1269 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1270 pFT_Done_Face(ft_face
);
1274 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1275 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1276 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1277 pFT_Done_Face(ft_face
);
1281 if(FT_IS_SFNT(ft_face
))
1283 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1284 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1285 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1287 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1288 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1289 pFT_Done_Face(ft_face
);
1293 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1294 we don't want to load these. */
1295 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1299 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1301 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1302 pFT_Done_Face(ft_face
);
1308 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1309 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1310 pFT_Done_Face(ft_face
);
1314 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1316 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1317 pFT_Done_Face(ft_face
);
1323 localised_family
= get_familyname(ft_face
);
1324 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1326 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1327 HeapFree(GetProcessHeap(), 0, localised_family
);
1328 num_faces
= ft_face
->num_faces
;
1329 pFT_Done_Face(ft_face
);
1332 HeapFree(GetProcessHeap(), 0, localised_family
);
1336 family_name
= ft_face
->family_name
;
1340 My_FT_Bitmap_Size
*size
= NULL
;
1343 if(!FT_IS_SCALABLE(ft_face
))
1344 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1346 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1347 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1348 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1350 localised_family
= NULL
;
1352 localised_family
= get_familyname(ft_face
);
1353 if(localised_family
&& !strcmpiW(localised_family
, english_family
)) {
1354 HeapFree(GetProcessHeap(), 0, localised_family
);
1355 localised_family
= NULL
;
1360 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1361 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1362 if(!strcmpiW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1367 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1368 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1369 list_init(&family
->faces
);
1370 list_add_tail(&font_list
, &family
->entry
);
1372 if(localised_family
) {
1373 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1374 subst
->from
.name
= strdupW(english_family
);
1375 subst
->from
.charset
= -1;
1376 subst
->to
.name
= strdupW(localised_family
);
1377 subst
->to
.charset
= -1;
1378 add_font_subst(&font_subst_list
, subst
, 0);
1381 HeapFree(GetProcessHeap(), 0, localised_family
);
1382 HeapFree(GetProcessHeap(), 0, english_family
);
1384 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1385 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1386 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1388 internal_leading
= 0;
1389 memset(&fs
, 0, sizeof(fs
));
1391 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1393 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1394 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1395 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1396 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1397 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1398 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1399 if(pOS2
->version
== 0) {
1402 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1403 fs
.fsCsb
[0] |= FS_LATIN1
;
1405 fs
.fsCsb
[0] |= FS_SYMBOL
;
1408 #ifdef HAVE_FREETYPE_FTWINFNT_H
1409 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1411 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1412 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1413 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1415 internal_leading
= winfnt_header
.internal_leading
;
1419 face_elem_ptr
= list_head(&family
->faces
);
1420 while(face_elem_ptr
) {
1421 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1422 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1423 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1424 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1425 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1426 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1427 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1430 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1431 HeapFree(GetProcessHeap(), 0, StyleW
);
1432 pFT_Done_Face(ft_face
);
1435 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1436 TRACE("Original font is newer so skipping this one\n");
1437 HeapFree(GetProcessHeap(), 0, StyleW
);
1438 pFT_Done_Face(ft_face
);
1441 TRACE("Replacing original with this one\n");
1442 list_remove(&face
->entry
);
1443 HeapFree(GetProcessHeap(), 0, face
->file
);
1444 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1445 HeapFree(GetProcessHeap(), 0, face
);
1450 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1451 face
->cached_enum_data
= NULL
;
1452 face
->StyleName
= StyleW
;
1455 face
->file
= strdupA(file
);
1456 face
->font_data_ptr
= NULL
;
1457 face
->font_data_size
= 0;
1462 face
->font_data_ptr
= font_data_ptr
;
1463 face
->font_data_size
= font_data_size
;
1465 face
->face_index
= face_index
;
1467 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1468 face
->ntmFlags
|= NTM_ITALIC
;
1469 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1470 face
->ntmFlags
|= NTM_BOLD
;
1471 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1472 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1473 face
->family
= family
;
1474 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1476 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1478 if(FT_IS_SCALABLE(ft_face
)) {
1479 memset(&face
->size
, 0, sizeof(face
->size
));
1480 face
->scalable
= TRUE
;
1482 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1483 size
->height
, size
->width
, size
->size
>> 6,
1484 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1485 face
->size
.height
= size
->height
;
1486 face
->size
.width
= size
->width
;
1487 face
->size
.size
= size
->size
;
1488 face
->size
.x_ppem
= size
->x_ppem
;
1489 face
->size
.y_ppem
= size
->y_ppem
;
1490 face
->size
.internal_leading
= internal_leading
;
1491 face
->scalable
= FALSE
;
1494 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1496 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1498 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1499 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1502 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1503 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1504 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1505 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1508 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1509 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1510 switch(ft_face
->charmaps
[i
]->encoding
) {
1511 case FT_ENCODING_UNICODE
:
1512 case FT_ENCODING_APPLE_ROMAN
:
1513 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1515 case FT_ENCODING_MS_SYMBOL
:
1516 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1524 AddFaceToFamily(face
, family
);
1526 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1528 num_faces
= ft_face
->num_faces
;
1529 pFT_Done_Face(ft_face
);
1530 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1531 debugstr_w(StyleW
));
1532 } while(num_faces
> ++face_index
);
1536 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1538 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1541 static void DumpFontList(void)
1545 struct list
*family_elem_ptr
, *face_elem_ptr
;
1547 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1548 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1549 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1550 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1551 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1552 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1554 TRACE(" %d", face
->size
.height
);
1561 /***********************************************************
1562 * The replacement list is a way to map an entire font
1563 * family onto another family. For example adding
1565 * [HKCU\Software\Wine\Fonts\Replacements]
1566 * "Wingdings"="Winedings"
1568 * would enumerate the Winedings font both as Winedings and
1569 * Wingdings. However if a real Wingdings font is present the
1570 * replacement does not take place.
1573 static void LoadReplaceList(void)
1576 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1581 struct list
*family_elem_ptr
, *face_elem_ptr
;
1584 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1585 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1587 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1588 &valuelen
, &datalen
, NULL
, NULL
);
1590 valuelen
++; /* returned value doesn't include room for '\0' */
1591 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1592 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1596 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1597 &dlen
) == ERROR_SUCCESS
) {
1598 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1599 /* "NewName"="Oldname" */
1600 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1602 /* Find the old family and hence all of the font files
1604 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1605 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1606 if(!strcmpiW(family
->FamilyName
, data
)) {
1607 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1608 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1609 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1610 debugstr_w(face
->StyleName
), familyA
);
1611 /* Now add a new entry with the new family name */
1612 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1617 /* reset dlen and vlen */
1621 HeapFree(GetProcessHeap(), 0, data
);
1622 HeapFree(GetProcessHeap(), 0, value
);
1627 /*************************************************************
1630 static BOOL
init_system_links(void)
1634 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1635 WCHAR
*value
, *data
;
1636 WCHAR
*entry
, *next
;
1637 SYSTEM_LINKS
*font_link
, *system_font_link
;
1638 CHILD_FONT
*child_font
;
1639 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1640 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1646 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1648 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1649 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1650 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1651 val_len
= max_val
+ 1;
1652 data_len
= max_data
;
1654 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1656 memset(&fs
, 0, sizeof(fs
));
1657 psub
= get_font_subst(&font_subst_list
, value
, -1);
1658 /* Don't store fonts that are only substitutes for other fonts */
1661 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1664 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1665 font_link
->font_name
= strdupW(value
);
1666 list_init(&font_link
->links
);
1667 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1670 CHILD_FONT
*child_font
;
1672 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1674 next
= entry
+ strlenW(entry
) + 1;
1676 face_name
= strchrW(entry
, ',');
1680 while(isspaceW(*face_name
))
1683 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1685 face_name
= psub
->to
.name
;
1687 face
= find_face_from_filename(entry
, face_name
);
1690 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1694 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1695 child_font
->face
= face
;
1696 child_font
->font
= NULL
;
1697 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1698 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1699 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1700 list_add_tail(&font_link
->links
, &child_font
->entry
);
1702 family
= find_family_from_name(font_link
->font_name
);
1705 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1707 face
->fs_links
= fs
;
1710 list_add_tail(&system_links
, &font_link
->entry
);
1712 val_len
= max_val
+ 1;
1713 data_len
= max_data
;
1716 HeapFree(GetProcessHeap(), 0, value
);
1717 HeapFree(GetProcessHeap(), 0, data
);
1721 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1724 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1725 system_font_link
->font_name
= strdupW(System
);
1726 list_init(&system_font_link
->links
);
1728 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1731 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1732 child_font
->face
= face
;
1733 child_font
->font
= NULL
;
1734 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1735 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1737 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1739 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1741 CHILD_FONT
*font_link_entry
;
1742 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1744 CHILD_FONT
*new_child
;
1745 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1746 new_child
->face
= font_link_entry
->face
;
1747 new_child
->font
= NULL
;
1748 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1753 list_add_tail(&system_links
, &system_font_link
->entry
);
1757 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1760 struct dirent
*dent
;
1761 char path
[MAX_PATH
];
1763 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1765 dir
= opendir(dirname
);
1767 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1770 while((dent
= readdir(dir
)) != NULL
) {
1771 struct stat statbuf
;
1773 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1776 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1778 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1780 if(stat(path
, &statbuf
) == -1)
1782 WARN("Can't stat %s\n", debugstr_a(path
));
1785 if(S_ISDIR(statbuf
.st_mode
))
1786 ReadFontDir(path
, external_fonts
);
1788 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1794 static void load_fontconfig_fonts(void)
1796 #ifdef SONAME_LIBFONTCONFIG
1797 void *fc_handle
= NULL
;
1806 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1808 TRACE("Wine cannot find the fontconfig library (%s).\n",
1809 SONAME_LIBFONTCONFIG
);
1812 #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;}
1813 LOAD_FUNCPTR(FcConfigGetCurrent
);
1814 LOAD_FUNCPTR(FcFontList
);
1815 LOAD_FUNCPTR(FcFontSetDestroy
);
1816 LOAD_FUNCPTR(FcInit
);
1817 LOAD_FUNCPTR(FcObjectSetAdd
);
1818 LOAD_FUNCPTR(FcObjectSetCreate
);
1819 LOAD_FUNCPTR(FcObjectSetDestroy
);
1820 LOAD_FUNCPTR(FcPatternCreate
);
1821 LOAD_FUNCPTR(FcPatternDestroy
);
1822 LOAD_FUNCPTR(FcPatternGetBool
);
1823 LOAD_FUNCPTR(FcPatternGetString
);
1826 if(!pFcInit()) return;
1828 config
= pFcConfigGetCurrent();
1829 pat
= pFcPatternCreate();
1830 os
= pFcObjectSetCreate();
1831 pFcObjectSetAdd(os
, FC_FILE
);
1832 pFcObjectSetAdd(os
, FC_SCALABLE
);
1833 fontset
= pFcFontList(config
, pat
, os
);
1834 if(!fontset
) return;
1835 for(i
= 0; i
< fontset
->nfont
; i
++) {
1838 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1840 TRACE("fontconfig: %s\n", file
);
1842 /* We're just interested in OT/TT fonts for now, so this hack just
1843 picks up the scalable fonts without extensions .pf[ab] to save time
1844 loading every other font */
1846 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1848 TRACE("not scalable\n");
1852 len
= strlen( file
);
1853 if(len
< 4) continue;
1854 ext
= &file
[ len
- 3 ];
1855 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1856 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1858 pFcFontSetDestroy(fontset
);
1859 pFcObjectSetDestroy(os
);
1860 pFcPatternDestroy(pat
);
1866 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1869 const char *data_dir
= wine_get_data_dir();
1871 if (!data_dir
) data_dir
= wine_get_build_dir();
1878 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1880 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1882 strcpy(unix_name
, data_dir
);
1883 strcat(unix_name
, "/fonts/");
1885 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1887 EnterCriticalSection( &freetype_cs
);
1888 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1889 LeaveCriticalSection( &freetype_cs
);
1890 HeapFree(GetProcessHeap(), 0, unix_name
);
1895 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1897 static const WCHAR slashW
[] = {'\\','\0'};
1899 WCHAR windowsdir
[MAX_PATH
];
1902 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1903 strcatW(windowsdir
, fontsW
);
1904 strcatW(windowsdir
, slashW
);
1905 strcatW(windowsdir
, file
);
1906 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1907 EnterCriticalSection( &freetype_cs
);
1908 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1909 LeaveCriticalSection( &freetype_cs
);
1910 HeapFree(GetProcessHeap(), 0, unixname
);
1915 static void load_system_fonts(void)
1918 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1919 const WCHAR
* const *value
;
1921 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1924 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1925 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1926 strcatW(windowsdir
, fontsW
);
1927 for(value
= SystemFontValues
; *value
; value
++) {
1928 dlen
= sizeof(data
);
1929 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1933 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1934 if((unixname
= wine_get_unix_file_name(pathW
))) {
1935 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1936 HeapFree(GetProcessHeap(), 0, unixname
);
1939 load_font_from_data_dir(data
);
1946 /*************************************************************
1948 * This adds registry entries for any externally loaded fonts
1949 * (fonts from fontconfig or FontDirs). It also deletes entries
1950 * of no longer existing fonts.
1953 static void update_reg_entries(void)
1955 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1960 struct list
*family_elem_ptr
, *face_elem_ptr
;
1962 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1963 static const WCHAR spaceW
[] = {' ', '\0'};
1966 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1967 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1968 ERR("Can't create Windows font reg key\n");
1972 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1973 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1974 ERR("Can't create Windows font reg key\n");
1978 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1979 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1980 ERR("Can't create external font reg key\n");
1984 /* enumerate the fonts and add external ones to the two keys */
1986 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1987 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1988 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1989 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1990 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1991 if(!face
->external
) continue;
1993 if (!(face
->ntmFlags
& NTM_REGULAR
))
1994 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1995 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1996 strcpyW(valueW
, family
->FamilyName
);
1997 if(len
!= len_fam
) {
1998 strcatW(valueW
, spaceW
);
1999 strcatW(valueW
, face
->StyleName
);
2001 strcatW(valueW
, TrueType
);
2003 file
= wine_get_dos_file_name(face
->file
);
2005 len
= strlenW(file
) + 1;
2008 if((path
= strrchr(face
->file
, '/')) == NULL
)
2012 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2014 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2015 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2017 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2018 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2019 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2021 HeapFree(GetProcessHeap(), 0, file
);
2022 HeapFree(GetProcessHeap(), 0, valueW
);
2026 if(external_key
) RegCloseKey(external_key
);
2027 if(win9x_key
) RegCloseKey(win9x_key
);
2028 if(winnt_key
) RegCloseKey(winnt_key
);
2032 static void delete_external_font_keys(void)
2034 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2035 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2039 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2040 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2041 ERR("Can't create Windows font reg key\n");
2045 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2046 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2047 ERR("Can't create Windows font reg key\n");
2051 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2052 ERR("Can't create external font reg key\n");
2056 /* Delete all external fonts added last time */
2058 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2059 &valuelen
, &datalen
, NULL
, NULL
);
2060 valuelen
++; /* returned value doesn't include room for '\0' */
2061 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2062 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2064 dlen
= datalen
* sizeof(WCHAR
);
2067 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2068 &dlen
) == ERROR_SUCCESS
) {
2070 RegDeleteValueW(winnt_key
, valueW
);
2071 RegDeleteValueW(win9x_key
, valueW
);
2072 /* reset dlen and vlen */
2076 HeapFree(GetProcessHeap(), 0, data
);
2077 HeapFree(GetProcessHeap(), 0, valueW
);
2079 /* Delete the old external fonts key */
2080 RegCloseKey(external_key
);
2081 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2084 if(win9x_key
) RegCloseKey(win9x_key
);
2085 if(winnt_key
) RegCloseKey(winnt_key
);
2088 /*************************************************************
2089 * WineEngAddFontResourceEx
2092 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2098 if (ft_handle
) /* do it only if we have freetype up and running */
2103 FIXME("Ignoring flags %x\n", flags
);
2105 if((unixname
= wine_get_unix_file_name(file
)))
2107 EnterCriticalSection( &freetype_cs
);
2108 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2109 LeaveCriticalSection( &freetype_cs
);
2110 HeapFree(GetProcessHeap(), 0, unixname
);
2112 if (!ret
&& !strchrW(file
, '\\')) {
2113 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2114 ret
= load_font_from_winfonts_dir(file
);
2116 /* Try in datadir/fonts (or builddir/fonts),
2117 * needed for Magic the Gathering Online
2119 ret
= load_font_from_data_dir(file
);
2126 /*************************************************************
2127 * WineEngAddFontMemResourceEx
2130 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2134 if (ft_handle
) /* do it only if we have freetype up and running */
2136 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2138 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2139 memcpy(pFontCopy
, pbFont
, cbFont
);
2141 EnterCriticalSection( &freetype_cs
);
2142 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2143 LeaveCriticalSection( &freetype_cs
);
2147 TRACE("AddFontToList failed\n");
2148 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2151 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2152 * For now return something unique but quite random
2154 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2155 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2162 /*************************************************************
2163 * WineEngRemoveFontResourceEx
2166 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2169 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2173 static const struct nls_update_font_list
2175 UINT ansi_cp
, oem_cp
;
2176 const char *oem
, *fixed
, *system
;
2177 const char *courier
, *serif
, *small
, *sserif
;
2178 /* these are for font substitutes */
2179 const char *shelldlg
, *tmsrmn
;
2180 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2184 const char *from
, *to
;
2185 } arial_0
, courier_new_0
, times_new_roman_0
;
2186 } nls_update_font_list
[] =
2188 /* Latin 1 (United States) */
2189 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2190 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2191 "Tahoma","Times New Roman",
2192 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2195 /* Latin 1 (Multilingual) */
2196 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2197 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2198 "Tahoma","Times New Roman", /* FIXME unverified */
2199 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2202 /* Eastern Europe */
2203 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2204 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,238", "System,238",
2207 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2208 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2209 { "Arial CE,0", "Arial,238" },
2210 { "Courier New CE,0", "Courier New,238" },
2211 { "Times New Roman CE,0", "Times New Roman,238" }
2214 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2215 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,204", "System,204",
2218 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2219 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2220 { "Arial Cyr,0", "Arial,204" },
2221 { "Courier New Cyr,0", "Courier New,204" },
2222 { "Times New Roman Cyr,0", "Times New Roman,204" }
2225 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2226 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,161", "System,161",
2229 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2230 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2231 { "Arial Greek,0", "Arial,161" },
2232 { "Courier New Greek,0", "Courier New,161" },
2233 { "Times New Roman Greek,0", "Times New Roman,161" }
2236 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2237 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2238 "Tahoma","Times New Roman", /* FIXME unverified */
2239 "Fixedsys,162", "System,162",
2240 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2241 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2242 { "Arial Tur,0", "Arial,162" },
2243 { "Courier New Tur,0", "Courier New,162" },
2244 { "Times New Roman Tur,0", "Times New Roman,162" }
2247 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2248 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2249 "Tahoma","Times New Roman", /* FIXME unverified */
2250 "Fixedsys,177", "System,177",
2251 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2252 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2256 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2257 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2258 "Tahoma","Times New Roman", /* FIXME unverified */
2259 "Fixedsys,178", "System,178",
2260 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2261 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2265 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2266 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2267 "Tahoma","Times New Roman", /* FIXME unverified */
2268 "Fixedsys,186", "System,186",
2269 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2270 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2271 { "Arial Baltic,0", "Arial,186" },
2272 { "Courier New Baltic,0", "Courier New,186" },
2273 { "Times New Roman Baltic,0", "Times New Roman,186" }
2276 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2277 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2283 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2284 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2285 "Tahoma","Times New Roman", /* FIXME unverified */
2286 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2290 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2291 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2292 "MS UI Gothic","MS Serif",
2293 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2296 /* Chinese Simplified */
2297 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2298 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2299 "SimSun", "NSimSun",
2300 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2304 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2307 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2310 /* Chinese Traditional */
2311 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2312 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2313 "PMingLiU", "MingLiU",
2314 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2319 static const WCHAR
*font_links_list
[] =
2321 Lucida_Sans_Unicode
,
2322 Microsoft_Sans_Serif
,
2326 static const struct font_links_defaults_list
2328 /* Keyed off substitution for "MS Shell Dlg" */
2329 const WCHAR
*shelldlg
;
2330 /* Maximum of four substitutes, plus terminating NULL pointer */
2331 const WCHAR
*substitutes
[5];
2332 } font_links_defaults_list
[] =
2334 /* Non East-Asian */
2335 { Tahoma
, /* FIXME unverified ordering */
2336 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2338 /* Below lists are courtesy of
2339 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2343 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2345 /* Chinese Simplified */
2347 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2351 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2353 /* Chinese Traditional */
2355 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2359 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2361 return ( ansi_cp
== 932 /* CP932 for Japanese */
2362 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2363 || ansi_cp
== 949 /* CP949 for Korean */
2364 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2367 static inline HKEY
create_fonts_NT_registry_key(void)
2371 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2372 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2376 static inline HKEY
create_fonts_9x_registry_key(void)
2380 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2381 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2385 static inline HKEY
create_config_fonts_registry_key(void)
2389 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2390 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2394 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2396 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2397 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2398 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2399 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2402 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2405 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2407 RegDeleteValueA(hkey
, name
);
2410 static void update_font_info(void)
2412 char buf
[40], cpbuf
[40];
2415 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2418 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2421 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2422 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2423 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2424 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2425 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2427 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2428 if (is_dbcs_ansi_cp(ansi_cp
))
2429 use_default_fallback
= TRUE
;
2432 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2434 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2439 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2441 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2443 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2446 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2450 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2451 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2453 hkey
= create_config_fonts_registry_key();
2454 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2455 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2456 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2459 hkey
= create_fonts_NT_registry_key();
2460 add_font_list(hkey
, &nls_update_font_list
[i
]);
2463 hkey
= create_fonts_9x_registry_key();
2464 add_font_list(hkey
, &nls_update_font_list
[i
]);
2467 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2469 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2470 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2471 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2472 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2474 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2475 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2476 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2477 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2478 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2479 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2480 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2481 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2483 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2484 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2485 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2493 /* Delete the FontSubstitutes from other locales */
2494 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2496 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2497 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2498 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2504 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2506 /* Clear out system links */
2507 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, system_link
);
2510 static void populate_system_links(HKEY hkey
, const WCHAR
*name
, const WCHAR
*const *values
)
2520 WCHAR buff
[MAX_PATH
];
2524 static const WCHAR comma
[] = {',',0};
2526 RegDeleteValueW(hkey
, name
);
2531 for (i
= 0; values
[i
] != NULL
; i
++)
2534 if (!strcmpiW(name
,value
))
2536 psub
= get_font_subst(&font_subst_list
, value
, -1);
2538 value
= psub
->to
.name
;
2539 family
= find_family_from_name(value
);
2543 /* Use first extant filename for this Family */
2544 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2548 file
= strrchr(face
->file
, '/');
2557 fileLen
= MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, NULL
, 0);
2558 fileW
= HeapAlloc(GetProcessHeap(), 0, fileLen
* sizeof(WCHAR
));
2559 MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, fileW
, fileLen
);
2560 entryLen
= strlenW(fileW
) + 1 + strlenW(value
) + 1;
2561 if (sizeof(buff
)-(data
-buff
) < entryLen
+ 1)
2563 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name
));
2564 HeapFree(GetProcessHeap(), 0, fileW
);
2567 strcpyW(data
, fileW
);
2568 strcatW(data
, comma
);
2569 strcatW(data
, value
);
2571 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2572 HeapFree(GetProcessHeap(), 0, fileW
);
2578 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (BYTE
*)buff
, (data
-buff
) * sizeof(WCHAR
));
2580 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name
));
2582 TRACE("removed SystemLink for %s\n", debugstr_w(name
));
2585 static void update_system_links(void)
2593 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2595 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE
, system_link
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, &disposition
))
2597 if (disposition
== REG_OPENED_EXISTING_KEY
)
2599 TRACE("SystemLink key already exists, doing nothing\n");
2604 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2606 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2611 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2613 if (!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
))
2615 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2616 populate_system_links(hkey
, font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2618 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2619 populate_system_links(hkey
, psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2622 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2624 populate_system_links(hkey
, font_links_defaults_list
[i
].substitutes
[0], NULL
);
2629 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub
->to
.name
));
2631 WARN("failed to create SystemLink key\n");
2635 static BOOL
init_freetype(void)
2637 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2640 "Wine cannot find the FreeType font library. To enable Wine to\n"
2641 "use TrueType fonts please install a version of FreeType greater than\n"
2642 "or equal to 2.0.5.\n"
2643 "http://www.freetype.org\n");
2647 #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;}
2649 LOAD_FUNCPTR(FT_Vector_Unit
)
2650 LOAD_FUNCPTR(FT_Done_Face
)
2651 LOAD_FUNCPTR(FT_Get_Char_Index
)
2652 LOAD_FUNCPTR(FT_Get_Module
)
2653 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2654 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2655 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2656 LOAD_FUNCPTR(FT_Init_FreeType
)
2657 LOAD_FUNCPTR(FT_Load_Glyph
)
2658 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2659 #ifndef FT_MULFIX_INLINED
2660 LOAD_FUNCPTR(FT_MulFix
)
2662 LOAD_FUNCPTR(FT_New_Face
)
2663 LOAD_FUNCPTR(FT_New_Memory_Face
)
2664 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2665 LOAD_FUNCPTR(FT_Outline_Transform
)
2666 LOAD_FUNCPTR(FT_Outline_Translate
)
2667 LOAD_FUNCPTR(FT_Select_Charmap
)
2668 LOAD_FUNCPTR(FT_Set_Charmap
)
2669 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2670 LOAD_FUNCPTR(FT_Vector_Transform
)
2671 LOAD_FUNCPTR(FT_Render_Glyph
)
2674 /* Don't warn if these ones are missing */
2675 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2676 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2677 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2678 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2679 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2680 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2681 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2683 #ifdef HAVE_FREETYPE_FTWINFNT_H
2684 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2686 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2687 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2688 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2689 <= 2.0.3 has FT_Sqrt64 */
2693 if(pFT_Init_FreeType(&library
) != 0) {
2694 ERR("Can't init FreeType library\n");
2695 wine_dlclose(ft_handle
, NULL
, 0);
2699 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2700 if (pFT_Library_Version
)
2701 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2703 if (FT_Version
.major
<=0)
2709 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2710 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2711 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2712 ((FT_Version
.patch
) & 0x0000ff);
2718 "Wine cannot find certain functions that it needs inside the FreeType\n"
2719 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2720 "FreeType to at least version 2.0.5.\n"
2721 "http://www.freetype.org\n");
2722 wine_dlclose(ft_handle
, NULL
, 0);
2727 /*************************************************************
2730 * Initialize FreeType library and create a list of available faces
2732 BOOL
WineEngInit(void)
2734 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2735 static const WCHAR pathW
[] = {'P','a','t','h',0};
2737 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2738 WCHAR windowsdir
[MAX_PATH
];
2741 const char *data_dir
;
2745 /* update locale dependent font info in registry */
2748 if(!init_freetype()) return FALSE
;
2750 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2751 ERR("Failed to create font mutex\n");
2754 WaitForSingleObject(font_mutex
, INFINITE
);
2756 delete_external_font_keys();
2758 /* load the system bitmap fonts */
2759 load_system_fonts();
2761 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2762 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2763 strcatW(windowsdir
, fontsW
);
2764 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2766 ReadFontDir(unixname
, FALSE
);
2767 HeapFree(GetProcessHeap(), 0, unixname
);
2770 /* load the system truetype fonts */
2771 data_dir
= wine_get_data_dir();
2772 if (!data_dir
) data_dir
= wine_get_build_dir();
2773 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2774 strcpy(unixname
, data_dir
);
2775 strcat(unixname
, "/fonts/");
2776 ReadFontDir(unixname
, TRUE
);
2777 HeapFree(GetProcessHeap(), 0, unixname
);
2780 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2781 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2782 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2784 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2785 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2786 &hkey
) == ERROR_SUCCESS
) {
2787 LPWSTR data
, valueW
;
2788 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2789 &valuelen
, &datalen
, NULL
, NULL
);
2791 valuelen
++; /* returned value doesn't include room for '\0' */
2792 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2793 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2796 dlen
= datalen
* sizeof(WCHAR
);
2798 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
2799 &dlen
) == ERROR_SUCCESS
) {
2800 if(data
[0] && (data
[1] == ':'))
2802 if((unixname
= wine_get_unix_file_name(data
)))
2804 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2805 HeapFree(GetProcessHeap(), 0, unixname
);
2808 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
2810 WCHAR pathW
[MAX_PATH
];
2811 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2814 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2815 if((unixname
= wine_get_unix_file_name(pathW
)))
2817 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2818 HeapFree(GetProcessHeap(), 0, unixname
);
2821 load_font_from_data_dir(data
);
2823 /* reset dlen and vlen */
2828 HeapFree(GetProcessHeap(), 0, data
);
2829 HeapFree(GetProcessHeap(), 0, valueW
);
2833 load_fontconfig_fonts();
2835 /* then look in any directories that we've specified in the config file */
2836 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2837 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2843 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2845 len
+= sizeof(WCHAR
);
2846 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2847 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2849 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2850 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2851 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2852 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2856 LPSTR next
= strchr( ptr
, ':' );
2857 if (next
) *next
++ = 0;
2858 ReadFontDir( ptr
, TRUE
);
2861 HeapFree( GetProcessHeap(), 0, valueA
);
2863 HeapFree( GetProcessHeap(), 0, valueW
);
2872 update_reg_entries();
2874 update_system_links();
2875 init_system_links();
2877 ReleaseMutex(font_mutex
);
2882 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2885 TT_HoriHeader
*pHori
;
2889 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2890 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2892 if(height
== 0) height
= 16;
2894 /* Calc. height of EM square:
2896 * For +ve lfHeight we have
2897 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2898 * Re-arranging gives:
2899 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2901 * For -ve lfHeight we have
2903 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2904 * with il = winAscent + winDescent - units_per_em]
2909 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2910 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2911 pHori
->Ascender
- pHori
->Descender
);
2913 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2914 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2922 static struct font_mapping
*map_font_file( const char *name
)
2924 struct font_mapping
*mapping
;
2928 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2929 if (fstat( fd
, &st
) == -1) goto error
;
2931 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2933 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2935 mapping
->refcount
++;
2940 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2943 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2946 if (mapping
->data
== MAP_FAILED
)
2948 HeapFree( GetProcessHeap(), 0, mapping
);
2951 mapping
->refcount
= 1;
2952 mapping
->dev
= st
.st_dev
;
2953 mapping
->ino
= st
.st_ino
;
2954 mapping
->size
= st
.st_size
;
2955 list_add_tail( &mappings_list
, &mapping
->entry
);
2963 static void unmap_font_file( struct font_mapping
*mapping
)
2965 if (!--mapping
->refcount
)
2967 list_remove( &mapping
->entry
);
2968 munmap( mapping
->data
, mapping
->size
);
2969 HeapFree( GetProcessHeap(), 0, mapping
);
2973 static LONG
load_VDMX(GdiFont
*, LONG
);
2975 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2982 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2986 if (!(font
->mapping
= map_font_file( face
->file
)))
2988 WARN("failed to map %s\n", debugstr_a(face
->file
));
2991 data_ptr
= font
->mapping
->data
;
2992 data_size
= font
->mapping
->size
;
2996 data_ptr
= face
->font_data_ptr
;
2997 data_size
= face
->font_data_size
;
3000 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3002 ERR("FT_New_Face rets %d\n", err
);
3006 /* set it here, as load_VDMX needs it */
3007 font
->ft_face
= ft_face
;
3009 if(FT_IS_SCALABLE(ft_face
)) {
3010 /* load the VDMX table if we have one */
3011 font
->ppem
= load_VDMX(font
, height
);
3013 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3014 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3016 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3017 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3019 font
->ppem
= height
;
3020 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3021 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3027 static int get_nearest_charset(Face
*face
, int *cp
)
3029 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3030 a single face with the requested charset. The idea is to check if
3031 the selected font supports the current ANSI codepage, if it does
3032 return the corresponding charset, else return the first charset */
3035 int acp
= GetACP(), i
;
3039 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3040 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3041 return csi
.ciCharset
;
3043 for(i
= 0; i
< 32; i
++) {
3045 if(face
->fs
.fsCsb
[0] & fs0
) {
3046 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3048 return csi
.ciCharset
;
3051 FIXME("TCI failing on %x\n", fs0
);
3055 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3056 face
->fs
.fsCsb
[0], face
->file
);
3058 return DEFAULT_CHARSET
;
3061 static GdiFont
*alloc_font(void)
3063 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3065 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3066 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3068 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3069 ret
->total_kern_pairs
= (DWORD
)-1;
3070 ret
->kern_pairs
= NULL
;
3071 list_init(&ret
->hfontlist
);
3072 list_init(&ret
->child_fonts
);
3076 static void free_font(GdiFont
*font
)
3078 struct list
*cursor
, *cursor2
;
3081 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3083 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3084 list_remove(cursor
);
3086 free_font(child
->font
);
3087 HeapFree(GetProcessHeap(), 0, child
);
3090 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3092 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3093 DeleteObject(hfontlist
->hfont
);
3094 list_remove(&hfontlist
->entry
);
3095 HeapFree(GetProcessHeap(), 0, hfontlist
);
3098 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3099 if (font
->mapping
) unmap_font_file( font
->mapping
);
3100 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3101 HeapFree(GetProcessHeap(), 0, font
->potm
);
3102 HeapFree(GetProcessHeap(), 0, font
->name
);
3103 for (i
= 0; i
< font
->gmsize
; i
++)
3104 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3105 HeapFree(GetProcessHeap(), 0, font
->gm
);
3106 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3107 HeapFree(GetProcessHeap(), 0, font
);
3111 /*************************************************************
3114 * load the vdmx entry for the specified height
3117 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3118 ( ( (FT_ULong)_x4 << 24 ) | \
3119 ( (FT_ULong)_x3 << 16 ) | \
3120 ( (FT_ULong)_x2 << 8 ) | \
3123 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3138 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3142 BYTE devXRatio
, devYRatio
;
3143 USHORT numRecs
, numRatios
;
3144 DWORD result
, offset
= -1;
3148 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3150 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3153 /* FIXME: need the real device aspect ratio */
3157 numRecs
= GET_BE_WORD(hdr
[1]);
3158 numRatios
= GET_BE_WORD(hdr
[2]);
3160 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3161 for(i
= 0; i
< numRatios
; i
++) {
3164 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3165 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3168 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3170 if((ratio
.xRatio
== 0 &&
3171 ratio
.yStartRatio
== 0 &&
3172 ratio
.yEndRatio
== 0) ||
3173 (devXRatio
== ratio
.xRatio
&&
3174 devYRatio
>= ratio
.yStartRatio
&&
3175 devYRatio
<= ratio
.yEndRatio
))
3177 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3178 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3179 offset
= GET_BE_WORD(tmp
);
3185 FIXME("No suitable ratio found\n");
3189 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3191 BYTE startsz
, endsz
;
3194 recs
= GET_BE_WORD(group
.recs
);
3195 startsz
= group
.startsz
;
3196 endsz
= group
.endsz
;
3198 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3200 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3201 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3202 if(result
== GDI_ERROR
) {
3203 FIXME("Failed to retrieve vTable\n");
3208 for(i
= 0; i
< recs
; i
++) {
3209 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3210 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3211 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3213 if(yMax
+ -yMin
== height
) {
3216 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3219 if(yMax
+ -yMin
> height
) {
3222 goto end
; /* failed */
3224 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3225 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3226 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3227 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3233 TRACE("ppem not found for height %d\n", height
);
3237 HeapFree(GetProcessHeap(), 0, vTable
);
3243 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3245 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3246 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3247 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3248 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3249 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3252 static void calc_hash(FONT_DESC
*pfd
)
3254 DWORD hash
= 0, *ptr
, two_chars
;
3258 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3260 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3262 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3264 pwc
= (WCHAR
*)&two_chars
;
3266 *pwc
= toupperW(*pwc
);
3268 *pwc
= toupperW(*pwc
);
3272 hash
^= !pfd
->can_use_bitmap
;
3277 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3282 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3286 fd
.can_use_bitmap
= can_use_bitmap
;
3289 /* try the child list */
3290 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3291 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3292 if(!fontcmp(ret
, &fd
)) {
3293 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3294 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3295 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3296 if(hflist
->hfont
== hfont
)
3302 /* try the in-use list */
3303 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3304 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3305 if(!fontcmp(ret
, &fd
)) {
3306 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3307 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3308 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3309 if(hflist
->hfont
== hfont
)
3312 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3313 hflist
->hfont
= hfont
;
3314 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3319 /* then the unused list */
3320 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3321 while(font_elem_ptr
) {
3322 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3323 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3324 if(!fontcmp(ret
, &fd
)) {
3325 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3326 assert(list_empty(&ret
->hfontlist
));
3327 TRACE("Found %p in unused list\n", ret
);
3328 list_remove(&ret
->entry
);
3329 list_add_head(&gdi_font_list
, &ret
->entry
);
3330 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3331 hflist
->hfont
= hfont
;
3332 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3339 static void add_to_cache(GdiFont
*font
)
3341 static DWORD cache_num
= 1;
3343 font
->cache_num
= cache_num
++;
3344 list_add_head(&gdi_font_list
, &font
->entry
);
3347 /*************************************************************
3348 * create_child_font_list
3350 static BOOL
create_child_font_list(GdiFont
*font
)
3353 SYSTEM_LINKS
*font_link
;
3354 CHILD_FONT
*font_link_entry
, *new_child
;
3358 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3359 font_name
= psub
? psub
->to
.name
: font
->name
;
3360 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3362 if(!strcmpiW(font_link
->font_name
, font_name
))
3364 TRACE("found entry in system list\n");
3365 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3367 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3368 new_child
->face
= font_link_entry
->face
;
3369 new_child
->font
= NULL
;
3370 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3371 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3378 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3379 * Sans Serif. This is how asian windows get default fallbacks for fonts
3381 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3382 font
->charset
!= OEM_CHARSET
&&
3383 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3384 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3386 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3388 TRACE("found entry in default fallback list\n");
3389 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3391 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3392 new_child
->face
= font_link_entry
->face
;
3393 new_child
->font
= NULL
;
3394 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3395 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3405 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3407 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3409 if (pFT_Set_Charmap
)
3412 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3414 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3416 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3418 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3420 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3421 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3423 switch (ft_face
->charmaps
[i
]->platform_id
)
3426 cmap_def
= ft_face
->charmaps
[i
];
3428 case 0: /* Apple Unicode */
3429 cmap0
= ft_face
->charmaps
[i
];
3431 case 1: /* Macintosh */
3432 cmap1
= ft_face
->charmaps
[i
];
3435 cmap2
= ft_face
->charmaps
[i
];
3437 case 3: /* Microsoft */
3438 cmap3
= ft_face
->charmaps
[i
];
3443 if (cmap3
) /* prefer Microsoft cmap table */
3444 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3446 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3448 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3450 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3452 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3454 return ft_err
== FT_Err_Ok
;
3457 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3460 /*************************************************************
3461 * WineEngCreateFontInstance
3464 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3467 Face
*face
, *best
, *best_bitmap
;
3468 Family
*family
, *last_resort_family
;
3469 struct list
*family_elem_ptr
, *face_elem_ptr
;
3470 INT height
, width
= 0;
3471 unsigned int score
= 0, new_score
;
3472 signed int diff
= 0, newdiff
;
3473 BOOL bd
, it
, can_use_bitmap
;
3478 FontSubst
*psub
= NULL
;
3480 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3481 lf
.lfWidth
= abs(lf
.lfWidth
);
3483 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3485 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3486 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3487 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3490 if(dc
->GraphicsMode
== GM_ADVANCED
)
3491 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3494 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3495 font scaling abilities. */
3496 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3497 dcmat
.eM21
= dcmat
.eM12
= 0;
3500 /* Try to avoid not necessary glyph transformations */
3501 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3503 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3504 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3505 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3508 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3509 dcmat
.eM21
, dcmat
.eM22
);
3512 EnterCriticalSection( &freetype_cs
);
3514 /* check the cache first */
3515 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3516 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3517 LeaveCriticalSection( &freetype_cs
);
3521 TRACE("not in cache\n");
3522 if(list_empty(&font_list
)) /* No fonts installed */
3524 TRACE("No fonts installed\n");
3525 LeaveCriticalSection( &freetype_cs
);
3531 ret
->font_desc
.matrix
= dcmat
;
3532 ret
->font_desc
.lf
= lf
;
3533 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3534 calc_hash(&ret
->font_desc
);
3535 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3536 hflist
->hfont
= hfont
;
3537 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3539 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3540 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3541 original value lfCharSet. Note this is a special case for
3542 Symbol and doesn't happen at least for "Wingdings*" */
3544 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3545 lf
.lfCharSet
= SYMBOL_CHARSET
;
3547 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3548 switch(lf
.lfCharSet
) {
3549 case DEFAULT_CHARSET
:
3550 csi
.fs
.fsCsb
[0] = 0;
3553 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3554 csi
.fs
.fsCsb
[0] = 0;
3560 if(lf
.lfFaceName
[0] != '\0') {
3561 SYSTEM_LINKS
*font_link
;
3562 CHILD_FONT
*font_link_entry
;
3563 LPWSTR FaceName
= lf
.lfFaceName
;
3566 * Check for a leading '@' this signals that the font is being
3567 * requested in tategaki mode (vertical writing substitution) but
3568 * does not affect the fontface that is to be selected.
3570 if (lf
.lfFaceName
[0]=='@')
3571 FaceName
= &lf
.lfFaceName
[1];
3573 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3576 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3577 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3578 if (psub
->to
.charset
!= -1)
3579 lf
.lfCharSet
= psub
->to
.charset
;
3582 /* We want a match on name and charset or just name if
3583 charset was DEFAULT_CHARSET. If the latter then
3584 we fixup the returned charset later in get_nearest_charset
3585 where we'll either use the charset of the current ansi codepage
3586 or if that's unavailable the first charset that the font supports.
3588 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3589 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3590 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3591 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3593 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3594 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3595 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3596 if(face
->scalable
|| can_use_bitmap
)
3603 * Try check the SystemLink list first for a replacement font.
3604 * We may find good replacements there.
3606 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3608 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3609 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3611 TRACE("found entry in system list\n");
3612 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3614 face
= font_link_entry
->face
;
3615 family
= face
->family
;
3616 if(csi
.fs
.fsCsb
[0] &
3617 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3619 if(face
->scalable
|| can_use_bitmap
)
3627 psub
= NULL
; /* substitution is no more relevant */
3629 /* If requested charset was DEFAULT_CHARSET then try using charset
3630 corresponding to the current ansi codepage */
3631 if (!csi
.fs
.fsCsb
[0])
3634 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3635 FIXME("TCI failed on codepage %d\n", acp
);
3636 csi
.fs
.fsCsb
[0] = 0;
3638 lf
.lfCharSet
= csi
.ciCharset
;
3641 /* Face families are in the top 4 bits of lfPitchAndFamily,
3642 so mask with 0xF0 before testing */
3644 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3645 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3646 strcpyW(lf
.lfFaceName
, defFixed
);
3647 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3648 strcpyW(lf
.lfFaceName
, defSerif
);
3649 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3650 strcpyW(lf
.lfFaceName
, defSans
);
3652 strcpyW(lf
.lfFaceName
, defSans
);
3653 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3654 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3655 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3656 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3657 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3658 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3659 if(face
->scalable
|| can_use_bitmap
)
3665 last_resort_family
= NULL
;
3666 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3667 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3668 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3669 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3670 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3673 if(can_use_bitmap
&& !last_resort_family
)
3674 last_resort_family
= family
;
3679 if(last_resort_family
) {
3680 family
= last_resort_family
;
3681 csi
.fs
.fsCsb
[0] = 0;
3685 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3686 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3687 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3688 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3689 if(face
->scalable
) {
3690 csi
.fs
.fsCsb
[0] = 0;
3691 WARN("just using first face for now\n");
3694 if(can_use_bitmap
&& !last_resort_family
)
3695 last_resort_family
= family
;
3698 if(!last_resort_family
) {
3699 FIXME("can't find a single appropriate font - bailing\n");
3701 LeaveCriticalSection( &freetype_cs
);
3705 WARN("could only find a bitmap font - this will probably look awful!\n");
3706 family
= last_resort_family
;
3707 csi
.fs
.fsCsb
[0] = 0;
3710 it
= lf
.lfItalic
? 1 : 0;
3711 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3713 height
= lf
.lfHeight
;
3715 face
= best
= best_bitmap
= NULL
;
3716 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3718 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3722 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3723 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3724 new_score
= (italic
^ it
) + (bold
^ bd
);
3725 if(!best
|| new_score
<= score
)
3727 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3728 italic
, bold
, it
, bd
);
3731 if(best
->scalable
&& score
== 0) break;
3735 newdiff
= height
- (signed int)(best
->size
.height
);
3737 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3738 if(!best_bitmap
|| new_score
< score
||
3739 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3741 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3744 if(score
== 0 && diff
== 0) break;
3751 face
= best
->scalable
? best
: best_bitmap
;
3752 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3753 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3757 if(csi
.fs
.fsCsb
[0]) {
3758 ret
->charset
= lf
.lfCharSet
;
3759 ret
->codepage
= csi
.ciACP
;
3762 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3764 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3765 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3767 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3769 if(!face
->scalable
) {
3770 /* Windows uses integer scaling factors for bitmap fonts */
3771 INT scale
, scaled_height
;
3772 GdiFont
*cachedfont
;
3774 /* FIXME: rotation of bitmap fonts is ignored */
3775 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3777 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3778 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3779 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3780 /* As we changed the matrix, we need to search the cache for the font again,
3781 * otherwise we might explode the cache. */
3782 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3783 TRACE("Found cached font after non-scalable matrix rescale!\n");
3785 LeaveCriticalSection( &freetype_cs
);
3788 calc_hash(&ret
->font_desc
);
3790 if (height
!= 0) height
= diff
;
3791 height
+= face
->size
.height
;
3793 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3794 scaled_height
= scale
* face
->size
.height
;
3795 /* Only jump to the next height if the difference <= 25% original height */
3796 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3797 /* The jump between unscaled and doubled is delayed by 1 */
3798 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3799 ret
->scale_y
= scale
;
3801 width
= face
->size
.x_ppem
>> 6;
3802 height
= face
->size
.y_ppem
>> 6;
3806 TRACE("font scale y: %f\n", ret
->scale_y
);
3808 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3813 LeaveCriticalSection( &freetype_cs
);
3817 ret
->ntmFlags
= face
->ntmFlags
;
3819 if (ret
->charset
== SYMBOL_CHARSET
&&
3820 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3823 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3827 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3830 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3831 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3832 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3833 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3834 create_child_font_list(ret
);
3836 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3838 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3839 if (length
!= GDI_ERROR
)
3841 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3842 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3843 TRACE("Loaded GSUB table of %i bytes\n",length
);
3847 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3850 LeaveCriticalSection( &freetype_cs
);
3854 static void dump_gdi_font_list(void)
3857 struct list
*elem_ptr
;
3859 TRACE("---------- gdiFont Cache ----------\n");
3860 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3861 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3862 TRACE("gdiFont=%p %s %d\n",
3863 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3866 TRACE("---------- Unused gdiFont Cache ----------\n");
3867 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3868 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3869 TRACE("gdiFont=%p %s %d\n",
3870 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3873 TRACE("---------- Child gdiFont Cache ----------\n");
3874 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
3875 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3876 TRACE("gdiFont=%p %s %d\n",
3877 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3881 /*************************************************************
3882 * WineEngDestroyFontInstance
3884 * free the gdiFont associated with this handle
3887 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3892 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3896 EnterCriticalSection( &freetype_cs
);
3898 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3900 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3901 while(hfontlist_elem_ptr
) {
3902 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3903 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3904 if(hflist
->hfont
== handle
) {
3905 TRACE("removing child font %p from child list\n", gdiFont
);
3906 list_remove(&gdiFont
->entry
);
3907 LeaveCriticalSection( &freetype_cs
);
3913 TRACE("destroying hfont=%p\n", handle
);
3915 dump_gdi_font_list();
3917 font_elem_ptr
= list_head(&gdi_font_list
);
3918 while(font_elem_ptr
) {
3919 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3920 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3922 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3923 while(hfontlist_elem_ptr
) {
3924 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3925 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3926 if(hflist
->hfont
== handle
) {
3927 list_remove(&hflist
->entry
);
3928 HeapFree(GetProcessHeap(), 0, hflist
);
3932 if(list_empty(&gdiFont
->hfontlist
)) {
3933 TRACE("Moving to Unused list\n");
3934 list_remove(&gdiFont
->entry
);
3935 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3940 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3941 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3942 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3943 while(font_elem_ptr
) {
3944 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3945 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3946 TRACE("freeing %p\n", gdiFont
);
3947 list_remove(&gdiFont
->entry
);
3950 LeaveCriticalSection( &freetype_cs
);
3954 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3955 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3960 if (face
->cached_enum_data
)
3963 *pelf
= face
->cached_enum_data
->elf
;
3964 *pntm
= face
->cached_enum_data
->ntm
;
3965 *ptype
= face
->cached_enum_data
->type
;
3969 font
= alloc_font();
3971 if(face
->scalable
) {
3972 height
= -2048; /* 2048 is the most common em size */
3975 height
= face
->size
.y_ppem
>> 6;
3976 width
= face
->size
.x_ppem
>> 6;
3978 font
->scale_y
= 1.0;
3980 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3986 font
->name
= strdupW(face
->family
->FamilyName
);
3987 font
->ntmFlags
= face
->ntmFlags
;
3989 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3991 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3993 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3995 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3996 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3998 lstrcpynW(pelf
->elfFullName
,
3999 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
4001 lstrcpynW(pelf
->elfStyle
,
4002 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4007 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4009 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4011 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4012 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4013 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4016 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4017 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4018 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4019 pntm
->ntmFontSig
= face
->fs
;
4021 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4023 pelf
->elfLogFont
.lfEscapement
= 0;
4024 pelf
->elfLogFont
.lfOrientation
= 0;
4025 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4026 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4027 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4028 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4029 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4030 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4031 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4032 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4033 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4034 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4035 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4038 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4039 *ptype
|= TRUETYPE_FONTTYPE
;
4040 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4041 *ptype
|= DEVICE_FONTTYPE
;
4042 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4043 *ptype
|= RASTER_FONTTYPE
;
4045 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4046 if (face
->cached_enum_data
)
4048 face
->cached_enum_data
->elf
= *pelf
;
4049 face
->cached_enum_data
->ntm
= *pntm
;
4050 face
->cached_enum_data
->type
= *ptype
;
4056 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4058 struct list
*face_elem_ptr
;
4060 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4062 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
)
4064 static const WCHAR spaceW
[] = { ' ',0 };
4065 WCHAR full_family_name
[LF_FULLFACESIZE
];
4066 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4068 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4070 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4071 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4075 strcpyW(full_family_name
, family
->FamilyName
);
4076 strcatW(full_family_name
, spaceW
);
4077 strcatW(full_family_name
, face
->StyleName
);
4078 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4084 static BOOL
face_matches(Face
*face
, const LOGFONTW
*lf
)
4086 static const WCHAR spaceW
[] = { ' ',0 };
4087 WCHAR full_family_name
[LF_FULLFACESIZE
];
4089 if (!strcmpiW(lf
->lfFaceName
, face
->family
->FamilyName
)) return TRUE
;
4091 if (strlenW(face
->family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4093 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4094 debugstr_w(face
->family
->FamilyName
), debugstr_w(face
->StyleName
));
4098 strcpyW(full_family_name
, face
->family
->FamilyName
);
4099 strcatW(full_family_name
, spaceW
);
4100 strcatW(full_family_name
, face
->StyleName
);
4101 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4104 static BOOL
enum_face_charsets(Face
*face
, FONTENUMPROCW proc
, LPARAM lparam
)
4107 NEWTEXTMETRICEXW ntm
;
4113 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4114 for(i
= 0; i
< 32; i
++) {
4115 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4116 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4117 strcpyW(elf
.elfScript
, OEM_DOSW
);
4118 i
= 32; /* break out of loop */
4119 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
4122 fs
.fsCsb
[0] = 1L << i
;
4124 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4125 csi
.ciCharset
= DEFAULT_CHARSET
;
4126 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
4127 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
4128 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
4130 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
4132 FIXME("Unknown elfscript for bit %d\n", i
);
4135 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4136 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4137 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4138 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
4139 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4140 ntm
.ntmTm
.ntmFlags
);
4141 /* release section before callback (FIXME) */
4142 LeaveCriticalSection( &freetype_cs
);
4143 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4144 EnterCriticalSection( &freetype_cs
);
4149 /*************************************************************
4153 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4157 struct list
*family_elem_ptr
, *face_elem_ptr
;
4162 lf
.lfCharSet
= DEFAULT_CHARSET
;
4163 lf
.lfPitchAndFamily
= 0;
4164 lf
.lfFaceName
[0] = 0;
4168 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4171 EnterCriticalSection( &freetype_cs
);
4172 if(plf
->lfFaceName
[0]) {
4174 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4177 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4178 debugstr_w(psub
->to
.name
));
4180 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4184 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4185 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4186 if(family_matches(family
, plf
)) {
4187 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4188 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4189 if (!face_matches(face
, plf
)) continue;
4190 if (!enum_face_charsets(face
, proc
, lparam
)) return 0;
4195 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4196 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4197 face_elem_ptr
= list_head(&family
->faces
);
4198 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4199 if (!enum_face_charsets(face
, proc
, lparam
)) return 0;
4202 LeaveCriticalSection( &freetype_cs
);
4206 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4208 pt
->x
.value
= vec
->x
>> 6;
4209 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4210 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4211 pt
->y
.value
= vec
->y
>> 6;
4212 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4213 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4217 /***************************************************
4218 * According to the MSDN documentation on WideCharToMultiByte,
4219 * certain codepages cannot set the default_used parameter.
4220 * This returns TRUE if the codepage can set that parameter, false else
4221 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4223 static BOOL
codepage_sets_default_used(UINT codepage
)
4237 * GSUB Table handling functions
4240 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4242 const GSUB_CoverageFormat1
* cf1
;
4246 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4248 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4250 TRACE("Coverage Format 1, %i glyphs\n",count
);
4251 for (i
= 0; i
< count
; i
++)
4252 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4256 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4258 const GSUB_CoverageFormat2
* cf2
;
4261 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4263 count
= GET_BE_WORD(cf2
->RangeCount
);
4264 TRACE("Coverage Format 2, %i ranges\n",count
);
4265 for (i
= 0; i
< count
; i
++)
4267 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4269 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4270 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4272 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4273 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4279 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4284 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4286 const GSUB_ScriptList
*script
;
4287 const GSUB_Script
*deflt
= NULL
;
4289 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4291 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4292 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4294 const GSUB_Script
*scr
;
4297 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4298 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4300 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4302 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4308 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4312 const GSUB_LangSys
*Lang
;
4314 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4316 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4318 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4319 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4321 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4324 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4327 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4333 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4336 const GSUB_FeatureList
*feature
;
4337 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4339 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4340 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4342 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4343 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4345 const GSUB_Feature
*feat
;
4346 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4353 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4357 const GSUB_LookupList
*lookup
;
4358 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4360 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4361 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4363 const GSUB_LookupTable
*look
;
4364 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4365 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4366 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4367 if (GET_BE_WORD(look
->LookupType
) != 1)
4368 FIXME("We only handle SubType 1\n");
4373 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4375 const GSUB_SingleSubstFormat1
*ssf1
;
4376 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4377 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4378 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4380 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4381 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4382 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4384 TRACE(" Glyph 0x%x ->",glyph
);
4385 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4386 TRACE(" 0x%x\n",glyph
);
4391 const GSUB_SingleSubstFormat2
*ssf2
;
4395 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4396 offset
= GET_BE_WORD(ssf1
->Coverage
);
4397 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4398 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4399 TRACE(" Coverage index %i\n",index
);
4402 TRACE(" Glyph is 0x%x ->",glyph
);
4403 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4404 TRACE("0x%x\n",glyph
);
4413 static const char* get_opentype_script(const GdiFont
*font
)
4416 * I am not sure if this is the correct way to generate our script tag
4419 switch (font
->charset
)
4421 case ANSI_CHARSET
: return "latn";
4422 case BALTIC_CHARSET
: return "latn"; /* ?? */
4423 case CHINESEBIG5_CHARSET
: return "hani";
4424 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4425 case GB2312_CHARSET
: return "hani";
4426 case GREEK_CHARSET
: return "grek";
4427 case HANGUL_CHARSET
: return "hang";
4428 case RUSSIAN_CHARSET
: return "cyrl";
4429 case SHIFTJIS_CHARSET
: return "kana";
4430 case TURKISH_CHARSET
: return "latn"; /* ?? */
4431 case VIETNAMESE_CHARSET
: return "latn";
4432 case JOHAB_CHARSET
: return "latn"; /* ?? */
4433 case ARABIC_CHARSET
: return "arab";
4434 case HEBREW_CHARSET
: return "hebr";
4435 case THAI_CHARSET
: return "thai";
4436 default: return "latn";
4440 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4442 const GSUB_Header
*header
;
4443 const GSUB_Script
*script
;
4444 const GSUB_LangSys
*language
;
4445 const GSUB_Feature
*feature
;
4447 if (!font
->GSUB_Table
)
4450 header
= font
->GSUB_Table
;
4452 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4455 TRACE("Script not found\n");
4458 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4461 TRACE("Language not found\n");
4464 feature
= GSUB_get_feature(header
, language
, "vrt2");
4466 feature
= GSUB_get_feature(header
, language
, "vert");
4469 TRACE("vrt2/vert feature not found\n");
4472 return GSUB_apply_feature(header
, feature
, glyph
);
4475 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4479 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4480 WCHAR wc
= (WCHAR
)glyph
;
4482 BOOL
*default_used_pointer
;
4485 default_used_pointer
= NULL
;
4486 default_used
= FALSE
;
4487 if (codepage_sets_default_used(font
->codepage
))
4488 default_used_pointer
= &default_used
;
4489 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4492 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4493 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4494 return get_GSUB_vert_glyph(font
,ret
);
4497 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4498 glyph
= glyph
+ 0xf000;
4499 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4500 return get_GSUB_vert_glyph(font
,glyphId
);
4503 /*************************************************************
4504 * WineEngGetGlyphIndices
4507 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4508 LPWORD pgi
, DWORD flags
)
4511 int default_char
= -1;
4513 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4515 for(i
= 0; i
< count
; i
++)
4517 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4520 if (default_char
== -1)
4522 if (FT_IS_SFNT(font
->ft_face
))
4524 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4525 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4530 WineEngGetTextMetrics(font
, &textm
);
4531 default_char
= textm
.tmDefaultChar
;
4534 pgi
[i
] = default_char
;
4540 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4542 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4543 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4546 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4548 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4549 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4552 /*************************************************************
4553 * WineEngGetGlyphOutline
4555 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4556 * except that the first parameter is the HWINEENGFONT of the font in
4557 * question rather than an HDC.
4560 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4561 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4564 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4565 FT_Face ft_face
= incoming_font
->ft_face
;
4566 GdiFont
*font
= incoming_font
;
4567 FT_UInt glyph_index
;
4568 DWORD width
, height
, pitch
, needed
= 0;
4569 FT_Bitmap ft_bitmap
;
4571 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4573 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4574 double widthRatio
= 1.0;
4575 FT_Matrix transMat
= identityMat
;
4576 FT_Matrix transMatUnrotated
;
4577 BOOL needsTransform
= FALSE
;
4578 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4579 UINT original_index
;
4581 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4582 buflen
, buf
, lpmat
);
4584 TRACE("font transform %f %f %f %f\n",
4585 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4586 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4589 EnterCriticalSection( &freetype_cs
);
4591 if(format
& GGO_GLYPH_INDEX
) {
4592 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4593 original_index
= glyph
;
4594 format
&= ~GGO_GLYPH_INDEX
;
4596 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4597 ft_face
= font
->ft_face
;
4598 original_index
= glyph_index
;
4601 if(format
& GGO_UNHINTED
) {
4602 load_flags
|= FT_LOAD_NO_HINTING
;
4603 format
&= ~GGO_UNHINTED
;
4606 /* tategaki never appears to happen to lower glyph index */
4607 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4610 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4611 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4612 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4613 font
->gmsize
* sizeof(GM
*));
4615 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4616 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
4618 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4619 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4620 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4621 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4622 LeaveCriticalSection( &freetype_cs
);
4623 return 1; /* FIXME */
4627 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4628 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4630 /* Scaling factor */
4635 WineEngGetTextMetrics(font
, &tm
);
4637 widthRatio
= (double)font
->aveWidth
;
4638 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4641 widthRatio
= font
->scale_y
;
4643 /* Scaling transform */
4644 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4647 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4650 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4652 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4653 needsTransform
= TRUE
;
4656 /* Slant transform */
4657 if (font
->fake_italic
) {
4660 slantMat
.xx
= (1 << 16);
4661 slantMat
.xy
= ((1 << 16) >> 2);
4663 slantMat
.yy
= (1 << 16);
4664 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4665 needsTransform
= TRUE
;
4668 /* Rotation transform */
4669 transMatUnrotated
= transMat
;
4670 if(font
->orientation
&& !tategaki
) {
4671 FT_Matrix rotationMat
;
4673 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4674 pFT_Vector_Unit(&vecAngle
, angle
);
4675 rotationMat
.xx
= vecAngle
.x
;
4676 rotationMat
.xy
= -vecAngle
.y
;
4677 rotationMat
.yx
= -rotationMat
.xy
;
4678 rotationMat
.yy
= rotationMat
.xx
;
4680 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4681 needsTransform
= TRUE
;
4684 /* World transform */
4685 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4688 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4689 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4690 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4691 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4692 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4693 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4694 needsTransform
= TRUE
;
4697 /* Extra transformation specified by caller */
4698 if (!is_identity_MAT2(lpmat
))
4701 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4702 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
4703 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
4704 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4705 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4706 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4707 needsTransform
= TRUE
;
4710 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4711 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4712 format
== GGO_GRAY8_BITMAP
))
4714 load_flags
|= FT_LOAD_NO_BITMAP
;
4717 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4720 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4721 LeaveCriticalSection( &freetype_cs
);
4725 if(!needsTransform
) {
4726 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4727 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4728 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
4730 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4731 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4732 ft_face
->glyph
->metrics
.height
) & -64;
4733 lpgm
->gmCellIncX
= adv
;
4734 lpgm
->gmCellIncY
= 0;
4741 for(xc
= 0; xc
< 2; xc
++) {
4742 for(yc
= 0; yc
< 2; yc
++) {
4743 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4744 xc
* ft_face
->glyph
->metrics
.width
);
4745 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4746 yc
* ft_face
->glyph
->metrics
.height
;
4747 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4748 pFT_Vector_Transform(&vec
, &transMat
);
4749 if(xc
== 0 && yc
== 0) {
4750 left
= right
= vec
.x
;
4751 top
= bottom
= vec
.y
;
4753 if(vec
.x
< left
) left
= vec
.x
;
4754 else if(vec
.x
> right
) right
= vec
.x
;
4755 if(vec
.y
< bottom
) bottom
= vec
.y
;
4756 else if(vec
.y
> top
) top
= vec
.y
;
4761 right
= (right
+ 63) & -64;
4762 bottom
= bottom
& -64;
4763 top
= (top
+ 63) & -64;
4765 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4766 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4768 pFT_Vector_Transform(&vec
, &transMat
);
4769 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4770 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4772 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4774 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4775 adv
= (vec
.x
+63) >> 6;
4779 bbx
= (right
- left
) >> 6;
4780 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4781 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4782 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4783 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4785 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4786 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4787 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4789 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4790 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
4792 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4793 FONT_GM(font
,original_index
)->adv
= adv
;
4794 FONT_GM(font
,original_index
)->lsb
= lsb
;
4795 FONT_GM(font
,original_index
)->bbx
= bbx
;
4796 FONT_GM(font
,original_index
)->init
= TRUE
;
4799 if(format
== GGO_METRICS
)
4801 LeaveCriticalSection( &freetype_cs
);
4802 return 1; /* FIXME */
4805 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
4806 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4807 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4808 format
== GGO_GRAY8_BITMAP
))
4810 TRACE("loaded a bitmap\n");
4811 LeaveCriticalSection( &freetype_cs
);
4817 width
= lpgm
->gmBlackBoxX
;
4818 height
= lpgm
->gmBlackBoxY
;
4819 pitch
= ((width
+ 31) >> 5) << 2;
4820 needed
= pitch
* height
;
4822 if(!buf
|| !buflen
) break;
4824 switch(ft_face
->glyph
->format
) {
4825 case ft_glyph_format_bitmap
:
4827 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4828 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4829 INT h
= ft_face
->glyph
->bitmap
.rows
;
4831 memcpy(dst
, src
, w
);
4832 src
+= ft_face
->glyph
->bitmap
.pitch
;
4838 case ft_glyph_format_outline
:
4839 ft_bitmap
.width
= width
;
4840 ft_bitmap
.rows
= height
;
4841 ft_bitmap
.pitch
= pitch
;
4842 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4843 ft_bitmap
.buffer
= buf
;
4846 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4848 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4850 /* Note: FreeType will only set 'black' bits for us. */
4851 memset(buf
, 0, needed
);
4852 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4856 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4857 LeaveCriticalSection( &freetype_cs
);
4862 case GGO_GRAY2_BITMAP
:
4863 case GGO_GRAY4_BITMAP
:
4864 case GGO_GRAY8_BITMAP
:
4865 case WINE_GGO_GRAY16_BITMAP
:
4867 unsigned int mult
, row
, col
;
4870 width
= lpgm
->gmBlackBoxX
;
4871 height
= lpgm
->gmBlackBoxY
;
4872 pitch
= (width
+ 3) / 4 * 4;
4873 needed
= pitch
* height
;
4875 if(!buf
|| !buflen
) break;
4877 switch(ft_face
->glyph
->format
) {
4878 case ft_glyph_format_bitmap
:
4880 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4881 INT h
= ft_face
->glyph
->bitmap
.rows
;
4884 for(x
= 0; x
< pitch
; x
++)
4886 if(x
< ft_face
->glyph
->bitmap
.width
)
4887 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4891 src
+= ft_face
->glyph
->bitmap
.pitch
;
4894 LeaveCriticalSection( &freetype_cs
);
4897 case ft_glyph_format_outline
:
4899 ft_bitmap
.width
= width
;
4900 ft_bitmap
.rows
= height
;
4901 ft_bitmap
.pitch
= pitch
;
4902 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4903 ft_bitmap
.buffer
= buf
;
4906 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4908 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4910 memset(ft_bitmap
.buffer
, 0, buflen
);
4912 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4914 if(format
== GGO_GRAY2_BITMAP
)
4916 else if(format
== GGO_GRAY4_BITMAP
)
4918 else if(format
== GGO_GRAY8_BITMAP
)
4920 else /* format == WINE_GGO_GRAY16_BITMAP */
4922 LeaveCriticalSection( &freetype_cs
);
4928 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4929 LeaveCriticalSection( &freetype_cs
);
4934 for(row
= 0; row
< height
; row
++) {
4936 for(col
= 0; col
< width
; col
++, ptr
++) {
4937 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4944 case WINE_GGO_HRGB_BITMAP
:
4945 case WINE_GGO_HBGR_BITMAP
:
4946 case WINE_GGO_VRGB_BITMAP
:
4947 case WINE_GGO_VBGR_BITMAP
:
4948 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4950 switch (ft_face
->glyph
->format
)
4952 case FT_GLYPH_FORMAT_BITMAP
:
4957 width
= lpgm
->gmBlackBoxX
;
4958 height
= lpgm
->gmBlackBoxY
;
4960 needed
= pitch
* height
;
4962 if (!buf
|| !buflen
) break;
4964 memset(buf
, 0, buflen
);
4966 src
= ft_face
->glyph
->bitmap
.buffer
;
4967 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
4971 for (x
= 0; x
< width
; x
++)
4973 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
4974 ((unsigned int *)dst
)[x
] = ~0u;
4983 case FT_GLYPH_FORMAT_OUTLINE
:
4987 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
4988 INT x_shift
, y_shift
;
4990 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
4991 FT_Render_Mode render_mode
=
4992 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
4993 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
4995 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
4997 if ( render_mode
== FT_RENDER_MODE_LCD
)
4999 lpgm
->gmBlackBoxX
+= 2;
5000 lpgm
->gmptGlyphOrigin
.x
-= 1;
5004 lpgm
->gmBlackBoxY
+= 2;
5005 lpgm
->gmptGlyphOrigin
.y
+= 1;
5009 width
= lpgm
->gmBlackBoxX
;
5010 height
= lpgm
->gmBlackBoxY
;
5012 needed
= pitch
* height
;
5014 if (!buf
|| !buflen
) break;
5016 memset(buf
, 0, buflen
);
5018 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5020 if ( needsTransform
)
5021 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5023 if ( pFT_Library_SetLcdFilter
)
5024 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5025 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5027 src
= ft_face
->glyph
->bitmap
.buffer
;
5028 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5029 src_width
= ft_face
->glyph
->bitmap
.width
;
5030 src_height
= ft_face
->glyph
->bitmap
.rows
;
5032 if ( render_mode
== FT_RENDER_MODE_LCD
)
5040 rgb_interval
= src_pitch
;
5045 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5046 if ( x_shift
< 0 ) x_shift
= 0;
5047 if ( x_shift
+ (src_width
/ hmul
) > width
)
5048 x_shift
= width
- (src_width
/ hmul
);
5050 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5051 if ( y_shift
< 0 ) y_shift
= 0;
5052 if ( y_shift
+ (src_height
/ vmul
) > height
)
5053 y_shift
= height
- (src_height
/ vmul
);
5055 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5056 while ( src_height
)
5058 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5062 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5063 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5064 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5065 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5069 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5070 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5071 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5072 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5075 src
+= src_pitch
* vmul
;
5084 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5085 LeaveCriticalSection ( &freetype_cs
);
5092 LeaveCriticalSection( &freetype_cs
);
5098 int contour
, point
= 0, first_pt
;
5099 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5100 TTPOLYGONHEADER
*pph
;
5102 DWORD pph_start
, cpfx
, type
;
5104 if(buflen
== 0) buf
= NULL
;
5106 if (needsTransform
&& buf
) {
5107 pFT_Outline_Transform(outline
, &transMat
);
5110 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5112 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5115 pph
->dwType
= TT_POLYGON_TYPE
;
5116 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5118 needed
+= sizeof(*pph
);
5120 while(point
<= outline
->contours
[contour
]) {
5121 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5122 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5123 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5127 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5130 } while(point
<= outline
->contours
[contour
] &&
5131 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5132 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5133 /* At the end of a contour Windows adds the start point, but
5135 if(point
> outline
->contours
[contour
] &&
5136 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5138 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5140 } else if(point
<= outline
->contours
[contour
] &&
5141 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5142 /* add closing pt for bezier */
5144 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5152 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5155 pph
->cb
= needed
- pph_start
;
5161 /* Convert the quadratic Beziers to cubic Beziers.
5162 The parametric eqn for a cubic Bezier is, from PLRM:
5163 r(t) = at^3 + bt^2 + ct + r0
5164 with the control points:
5169 A quadratic Beizer has the form:
5170 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5172 So equating powers of t leads to:
5173 r1 = 2/3 p1 + 1/3 p0
5174 r2 = 2/3 p1 + 1/3 p2
5175 and of course r0 = p0, r3 = p2
5178 int contour
, point
= 0, first_pt
;
5179 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5180 TTPOLYGONHEADER
*pph
;
5182 DWORD pph_start
, cpfx
, type
;
5183 FT_Vector cubic_control
[4];
5184 if(buflen
== 0) buf
= NULL
;
5186 if (needsTransform
&& buf
) {
5187 pFT_Outline_Transform(outline
, &transMat
);
5190 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5192 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5195 pph
->dwType
= TT_POLYGON_TYPE
;
5196 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5198 needed
+= sizeof(*pph
);
5200 while(point
<= outline
->contours
[contour
]) {
5201 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5202 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5203 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5206 if(type
== TT_PRIM_LINE
) {
5208 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5212 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5215 /* FIXME: Possible optimization in endpoint calculation
5216 if there are two consecutive curves */
5217 cubic_control
[0] = outline
->points
[point
-1];
5218 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5219 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5220 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5221 cubic_control
[0].x
>>= 1;
5222 cubic_control
[0].y
>>= 1;
5224 if(point
+1 > outline
->contours
[contour
])
5225 cubic_control
[3] = outline
->points
[first_pt
];
5227 cubic_control
[3] = outline
->points
[point
+1];
5228 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5229 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5230 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5231 cubic_control
[3].x
>>= 1;
5232 cubic_control
[3].y
>>= 1;
5235 /* r1 = 1/3 p0 + 2/3 p1
5236 r2 = 1/3 p2 + 2/3 p1 */
5237 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5238 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5239 cubic_control
[2] = cubic_control
[1];
5240 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5241 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5242 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5243 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5245 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5246 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5247 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5252 } while(point
<= outline
->contours
[contour
] &&
5253 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5254 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5255 /* At the end of a contour Windows adds the start point,
5256 but only for Beziers and we've already done that.
5258 if(point
<= outline
->contours
[contour
] &&
5259 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5260 /* This is the closing pt of a bezier, but we've already
5261 added it, so just inc point and carry on */
5268 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5271 pph
->cb
= needed
- pph_start
;
5277 FIXME("Unsupported format %d\n", format
);
5278 LeaveCriticalSection( &freetype_cs
);
5281 LeaveCriticalSection( &freetype_cs
);
5285 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5287 FT_Face ft_face
= font
->ft_face
;
5288 #ifdef HAVE_FREETYPE_FTWINFNT_H
5289 FT_WinFNT_HeaderRec winfnt_header
;
5291 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5292 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5293 font
->potm
->otmSize
= size
;
5295 #define TM font->potm->otmTextMetrics
5296 #ifdef HAVE_FREETYPE_FTWINFNT_H
5297 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5299 TM
.tmHeight
= winfnt_header
.pixel_height
;
5300 TM
.tmAscent
= winfnt_header
.ascent
;
5301 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5302 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5303 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5304 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5305 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5306 TM
.tmWeight
= winfnt_header
.weight
;
5308 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5309 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5310 TM
.tmFirstChar
= winfnt_header
.first_char
;
5311 TM
.tmLastChar
= winfnt_header
.last_char
;
5312 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5313 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5314 TM
.tmItalic
= winfnt_header
.italic
;
5315 TM
.tmUnderlined
= font
->underline
;
5316 TM
.tmStruckOut
= font
->strikeout
;
5317 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5318 TM
.tmCharSet
= winfnt_header
.charset
;
5323 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5324 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5325 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5326 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5327 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5328 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5329 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5330 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5332 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5333 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5335 TM
.tmLastChar
= 255;
5336 TM
.tmDefaultChar
= 32;
5337 TM
.tmBreakChar
= 32;
5338 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5339 TM
.tmUnderlined
= font
->underline
;
5340 TM
.tmStruckOut
= font
->strikeout
;
5341 /* NB inverted meaning of TMPF_FIXED_PITCH */
5342 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5343 TM
.tmCharSet
= font
->charset
;
5351 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5353 double scale_x
, scale_y
;
5357 scale_x
= (double)font
->aveWidth
;
5358 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5361 scale_x
= font
->scale_y
;
5363 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5364 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5366 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5367 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5369 SCALE_Y(ptm
->tmHeight
);
5370 SCALE_Y(ptm
->tmAscent
);
5371 SCALE_Y(ptm
->tmDescent
);
5372 SCALE_Y(ptm
->tmInternalLeading
);
5373 SCALE_Y(ptm
->tmExternalLeading
);
5374 SCALE_Y(ptm
->tmOverhang
);
5376 SCALE_X(ptm
->tmAveCharWidth
);
5377 SCALE_X(ptm
->tmMaxCharWidth
);
5383 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5385 double scale_x
, scale_y
;
5389 scale_x
= (double)font
->aveWidth
;
5390 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5393 scale_x
= font
->scale_y
;
5395 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5396 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5398 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5400 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5401 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5403 SCALE_Y(potm
->otmAscent
);
5404 SCALE_Y(potm
->otmDescent
);
5405 SCALE_Y(potm
->otmLineGap
);
5406 SCALE_Y(potm
->otmsCapEmHeight
);
5407 SCALE_Y(potm
->otmsXHeight
);
5408 SCALE_Y(potm
->otmrcFontBox
.top
);
5409 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5410 SCALE_X(potm
->otmrcFontBox
.left
);
5411 SCALE_X(potm
->otmrcFontBox
.right
);
5412 SCALE_Y(potm
->otmMacAscent
);
5413 SCALE_Y(potm
->otmMacDescent
);
5414 SCALE_Y(potm
->otmMacLineGap
);
5415 SCALE_X(potm
->otmptSubscriptSize
.x
);
5416 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5417 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5418 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5419 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5420 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5421 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5422 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5423 SCALE_Y(potm
->otmsStrikeoutSize
);
5424 SCALE_Y(potm
->otmsStrikeoutPosition
);
5425 SCALE_Y(potm
->otmsUnderscoreSize
);
5426 SCALE_Y(potm
->otmsUnderscorePosition
);
5432 /*************************************************************
5433 * WineEngGetTextMetrics
5436 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5439 EnterCriticalSection( &freetype_cs
);
5441 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5442 if(!get_bitmap_text_metrics(font
))
5444 LeaveCriticalSection( &freetype_cs
);
5448 /* Make sure that the font has sane width/height ratio */
5451 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
5453 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
5459 *ptm
= font
->potm
->otmTextMetrics
;
5460 scale_font_metrics(font
, ptm
);
5461 LeaveCriticalSection( &freetype_cs
);
5465 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5469 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5471 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
5477 /*************************************************************
5478 * WineEngGetOutlineTextMetrics
5481 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5482 OUTLINETEXTMETRICW
*potm
)
5484 FT_Face ft_face
= font
->ft_face
;
5485 UINT needed
, lenfam
, lensty
, ret
;
5487 TT_HoriHeader
*pHori
;
5488 TT_Postscript
*pPost
;
5489 FT_Fixed x_scale
, y_scale
;
5490 WCHAR
*family_nameW
, *style_nameW
;
5491 static const WCHAR spaceW
[] = {' ', '\0'};
5493 INT ascent
, descent
;
5495 TRACE("font=%p\n", font
);
5497 if(!FT_IS_SCALABLE(ft_face
))
5501 EnterCriticalSection( &freetype_cs
);
5504 if(cbSize
>= font
->potm
->otmSize
)
5506 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5507 scale_outline_font_metrics(font
, potm
);
5509 LeaveCriticalSection( &freetype_cs
);
5510 return font
->potm
->otmSize
;
5514 needed
= sizeof(*potm
);
5516 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5517 family_nameW
= strdupW(font
->name
);
5519 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5521 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5522 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5523 style_nameW
, lensty
/sizeof(WCHAR
));
5525 /* These names should be read from the TT name table */
5527 /* length of otmpFamilyName */
5530 /* length of otmpFaceName */
5531 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5532 needed
+= lenfam
; /* just the family name */
5534 needed
+= lenfam
+ lensty
; /* family + " " + style */
5537 /* length of otmpStyleName */
5540 /* length of otmpFullName */
5541 needed
+= lenfam
+ lensty
;
5544 x_scale
= ft_face
->size
->metrics
.x_scale
;
5545 y_scale
= ft_face
->size
->metrics
.y_scale
;
5547 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5549 FIXME("Can't find OS/2 table - not TT font?\n");
5554 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5556 FIXME("Can't find HHEA table - not TT font?\n");
5561 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5563 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",
5564 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5565 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5566 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5567 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5568 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5570 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5571 font
->potm
->otmSize
= needed
;
5573 #define TM font->potm->otmTextMetrics
5575 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5576 ascent
= pHori
->Ascender
;
5577 descent
= -pHori
->Descender
;
5579 ascent
= pOS2
->usWinAscent
;
5580 descent
= pOS2
->usWinDescent
;
5584 TM
.tmAscent
= font
->yMax
;
5585 TM
.tmDescent
= -font
->yMin
;
5586 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5588 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5589 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5590 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5591 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5594 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5597 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5599 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5600 ((ascent
+ descent
) -
5601 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5603 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5604 if (TM
.tmAveCharWidth
== 0) {
5605 TM
.tmAveCharWidth
= 1;
5607 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5608 TM
.tmWeight
= FW_REGULAR
;
5609 if (font
->fake_bold
)
5610 TM
.tmWeight
= FW_BOLD
;
5613 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
5615 if (pOS2
->usWeightClass
> FW_MEDIUM
)
5616 TM
.tmWeight
= pOS2
->usWeightClass
;
5618 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
5619 TM
.tmWeight
= pOS2
->usWeightClass
;
5622 TM
.tmDigitizedAspectX
= 300;
5623 TM
.tmDigitizedAspectY
= 300;
5624 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5625 * symbol range to 0 - f0ff
5628 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
5633 case 1257: /* Baltic */
5634 TM
.tmLastChar
= 0xf8fd;
5637 TM
.tmLastChar
= 0xf0ff;
5639 TM
.tmBreakChar
= 0x20;
5640 TM
.tmDefaultChar
= 0x1f;
5644 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
5645 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
5647 if(pOS2
->usFirstCharIndex
<= 1)
5648 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
5649 else if (pOS2
->usFirstCharIndex
> 0xff)
5650 TM
.tmBreakChar
= 0x20;
5652 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
5653 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
5655 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5656 TM
.tmUnderlined
= font
->underline
;
5657 TM
.tmStruckOut
= font
->strikeout
;
5659 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5660 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5661 (pOS2
->version
== 0xFFFFU
||
5662 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5663 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5665 TM
.tmPitchAndFamily
= 0;
5667 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
5669 case PAN_FAMILY_SCRIPT
:
5670 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5673 case PAN_FAMILY_DECORATIVE
:
5674 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5679 case PAN_FAMILY_TEXT_DISPLAY
:
5680 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
5681 /* which is clearly not what the panose spec says. */
5683 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
5684 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
5685 TM
.tmPitchAndFamily
= FF_MODERN
;
5688 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
5693 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5696 case PAN_SERIF_COVE
:
5697 case PAN_SERIF_OBTUSE_COVE
:
5698 case PAN_SERIF_SQUARE_COVE
:
5699 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
5700 case PAN_SERIF_SQUARE
:
5701 case PAN_SERIF_THIN
:
5702 case PAN_SERIF_BONE
:
5703 case PAN_SERIF_EXAGGERATED
:
5704 case PAN_SERIF_TRIANGLE
:
5705 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5708 case PAN_SERIF_NORMAL_SANS
:
5709 case PAN_SERIF_OBTUSE_SANS
:
5710 case PAN_SERIF_PERP_SANS
:
5711 case PAN_SERIF_FLARED
:
5712 case PAN_SERIF_ROUNDED
:
5713 TM
.tmPitchAndFamily
|= FF_SWISS
;
5720 if(FT_IS_SCALABLE(ft_face
))
5721 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5723 if(FT_IS_SFNT(ft_face
))
5725 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5726 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5728 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5731 TM
.tmCharSet
= font
->charset
;
5733 font
->potm
->otmFiller
= 0;
5734 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5735 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5736 font
->potm
->otmfsType
= pOS2
->fsType
;
5737 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5738 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5739 font
->potm
->otmItalicAngle
= 0; /* POST table */
5740 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5741 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5742 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5743 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5744 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5745 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5746 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5747 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5748 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5749 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5750 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5751 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5752 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5753 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5754 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5755 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5756 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5757 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5758 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5759 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5760 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5761 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5762 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5763 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5765 font
->potm
->otmsUnderscoreSize
= 0;
5766 font
->potm
->otmsUnderscorePosition
= 0;
5768 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5769 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5773 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5774 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5775 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5776 strcpyW((WCHAR
*)cp
, family_nameW
);
5778 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5779 strcpyW((WCHAR
*)cp
, style_nameW
);
5781 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5782 strcpyW((WCHAR
*)cp
, family_nameW
);
5783 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5784 strcatW((WCHAR
*)cp
, spaceW
);
5785 strcatW((WCHAR
*)cp
, style_nameW
);
5786 cp
+= lenfam
+ lensty
;
5789 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5790 strcpyW((WCHAR
*)cp
, family_nameW
);
5791 strcatW((WCHAR
*)cp
, spaceW
);
5792 strcatW((WCHAR
*)cp
, style_nameW
);
5795 if(potm
&& needed
<= cbSize
)
5797 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5798 scale_outline_font_metrics(font
, potm
);
5802 HeapFree(GetProcessHeap(), 0, style_nameW
);
5803 HeapFree(GetProcessHeap(), 0, family_nameW
);
5805 LeaveCriticalSection( &freetype_cs
);
5809 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5811 HFONTLIST
*hfontlist
;
5812 child
->font
= alloc_font();
5813 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5814 if(!child
->font
->ft_face
)
5816 free_font(child
->font
);
5821 child
->font
->font_desc
= font
->font_desc
;
5822 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5823 child
->font
->orientation
= font
->orientation
;
5824 child
->font
->scale_y
= font
->scale_y
;
5825 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5826 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5827 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
5828 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5829 child
->font
->base_font
= font
;
5830 list_add_head(&child_font_list
, &child
->font
->entry
);
5831 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5835 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5838 CHILD_FONT
*child_font
;
5841 font
= font
->base_font
;
5843 *linked_font
= font
;
5845 if((*glyph
= get_glyph_index(font
, c
)))
5848 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5850 if(!child_font
->font
)
5851 if(!load_child_font(font
, child_font
))
5854 if(!child_font
->font
->ft_face
)
5856 g
= get_glyph_index(child_font
->font
, c
);
5860 *linked_font
= child_font
->font
;
5867 /*************************************************************
5868 * WineEngGetCharWidth
5871 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5874 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5877 FT_UInt glyph_index
;
5878 GdiFont
*linked_font
;
5880 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5883 EnterCriticalSection( &freetype_cs
);
5884 for(c
= firstChar
; c
<= lastChar
; c
++) {
5885 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5886 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5887 &gm
, 0, NULL
, &identity
);
5888 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5890 LeaveCriticalSection( &freetype_cs
);
5894 /*************************************************************
5895 * WineEngGetCharABCWidths
5898 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5901 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5904 FT_UInt glyph_index
;
5905 GdiFont
*linked_font
;
5907 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5909 if(!FT_IS_SCALABLE(font
->ft_face
))
5913 EnterCriticalSection( &freetype_cs
);
5915 for(c
= firstChar
; c
<= lastChar
; c
++) {
5916 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5917 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5918 &gm
, 0, NULL
, &identity
);
5919 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5920 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5921 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5922 FONT_GM(linked_font
,glyph_index
)->bbx
;
5924 LeaveCriticalSection( &freetype_cs
);
5928 /*************************************************************
5929 * WineEngGetCharABCWidthsFloat
5932 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
5934 static const MAT2 identity
= {{0,1}, {0,0}, {0,0}, {0,1}};
5937 FT_UInt glyph_index
;
5938 GdiFont
*linked_font
;
5940 TRACE("%p, %d, %d, %p\n", font
, first
, last
, buffer
);
5943 EnterCriticalSection( &freetype_cs
);
5945 for (c
= first
; c
<= last
; c
++)
5947 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5948 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5949 &gm
, 0, NULL
, &identity
);
5950 buffer
[c
- first
].abcfA
= FONT_GM(linked_font
, glyph_index
)->lsb
;
5951 buffer
[c
- first
].abcfB
= FONT_GM(linked_font
, glyph_index
)->bbx
;
5952 buffer
[c
- first
].abcfC
= FONT_GM(linked_font
, glyph_index
)->adv
-
5953 FONT_GM(linked_font
, glyph_index
)->lsb
-
5954 FONT_GM(linked_font
, glyph_index
)->bbx
;
5956 LeaveCriticalSection( &freetype_cs
);
5960 /*************************************************************
5961 * WineEngGetCharABCWidthsI
5964 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5967 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5970 FT_UInt glyph_index
;
5971 GdiFont
*linked_font
;
5973 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5977 EnterCriticalSection( &freetype_cs
);
5979 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5981 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5982 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5983 &gm
, 0, NULL
, &identity
);
5984 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5985 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5986 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5987 - FONT_GM(linked_font
,c
)->bbx
;
5990 for(c
= 0; c
< count
; c
++) {
5991 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5992 &gm
, 0, NULL
, &identity
);
5993 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5994 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5995 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5996 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5999 LeaveCriticalSection( &freetype_cs
);
6003 /*************************************************************
6004 * WineEngGetTextExtentExPoint
6007 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6008 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6010 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6015 FT_UInt glyph_index
;
6016 GdiFont
*linked_font
;
6018 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
6022 EnterCriticalSection( &freetype_cs
);
6025 WineEngGetTextMetrics(font
, &tm
);
6026 size
->cy
= tm
.tmHeight
;
6028 for(idx
= 0; idx
< count
; idx
++) {
6029 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
6030 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6031 &gm
, 0, NULL
, &identity
);
6032 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6034 if (! pnfit
|| ext
<= max_ext
) {
6044 LeaveCriticalSection( &freetype_cs
);
6045 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6049 /*************************************************************
6050 * WineEngGetTextExtentExPointI
6053 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6054 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6056 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6062 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
6065 EnterCriticalSection( &freetype_cs
);
6068 WineEngGetTextMetrics(font
, &tm
);
6069 size
->cy
= tm
.tmHeight
;
6071 for(idx
= 0; idx
< count
; idx
++) {
6072 WineEngGetGlyphOutline(font
, indices
[idx
],
6073 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
6075 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
6077 if (! pnfit
|| ext
<= max_ext
) {
6087 LeaveCriticalSection( &freetype_cs
);
6088 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6092 /*************************************************************
6093 * WineEngGetFontData
6096 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6099 FT_Face ft_face
= font
->ft_face
;
6103 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6104 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6105 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6107 if(!FT_IS_SFNT(ft_face
))
6115 if(table
) { /* MS tags differ in endianness from FT ones */
6116 table
= table
>> 24 | table
<< 24 |
6117 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
6120 /* make sure value of len is the value freetype says it needs */
6123 FT_ULong needed
= 0;
6124 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
6125 if( !err
&& needed
< len
) len
= needed
;
6127 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
6130 TRACE("Can't find table %c%c%c%c\n",
6131 /* bytes were reversed */
6132 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
6133 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
6139 /*************************************************************
6140 * WineEngGetTextFace
6143 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6145 INT n
= strlenW(font
->name
) + 1;
6147 lstrcpynW(str
, font
->name
, count
);
6148 return min(count
, n
);
6153 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6155 if (fs
) *fs
= font
->fs
;
6156 return font
->charset
;
6159 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6161 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6162 struct list
*first_hfont
;
6166 EnterCriticalSection( &freetype_cs
);
6167 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6168 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6169 if(font
== linked_font
)
6170 *new_hfont
= dc
->hFont
;
6173 first_hfont
= list_head(&linked_font
->hfontlist
);
6174 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6176 LeaveCriticalSection( &freetype_cs
);
6180 /* Retrieve a list of supported Unicode ranges for a given font.
6181 * Can be called with NULL gs to calculate the buffer size. Returns
6182 * the number of ranges found.
6184 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6186 DWORD num_ranges
= 0;
6188 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6191 FT_ULong char_code
, char_code_prev
;
6194 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6196 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6197 face
->num_glyphs
, glyph_code
, char_code
);
6199 if (!glyph_code
) return 0;
6203 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6204 gs
->ranges
[0].cGlyphs
= 0;
6205 gs
->cGlyphsSupported
= 0;
6211 if (char_code
< char_code_prev
)
6213 ERR("expected increasing char code from FT_Get_Next_Char\n");
6216 if (char_code
- char_code_prev
> 1)
6221 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6222 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6223 gs
->cGlyphsSupported
++;
6228 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6229 gs
->cGlyphsSupported
++;
6231 char_code_prev
= char_code
;
6232 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6236 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6241 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6244 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
6246 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6249 glyphset
->cbThis
= size
;
6250 glyphset
->cRanges
= num_ranges
;
6251 glyphset
->flAccel
= 0;
6256 /*************************************************************
6259 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6263 EnterCriticalSection( &freetype_cs
);
6264 ret
= !list_empty(&font
->child_fonts
);
6265 LeaveCriticalSection( &freetype_cs
);
6269 static BOOL
is_hinting_enabled(void)
6271 /* Use the >= 2.2.0 function if available */
6272 if(pFT_Get_TrueType_Engine_Type
)
6274 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6275 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6277 #ifdef FT_DRIVER_HAS_HINTER
6282 /* otherwise if we've been compiled with < 2.2.0 headers
6283 use the internal macro */
6284 mod
= pFT_Get_Module(library
, "truetype");
6285 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6293 static BOOL
is_subpixel_rendering_enabled( void )
6295 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6296 return pFT_Library_SetLcdFilter
&&
6297 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6303 /*************************************************************************
6304 * GetRasterizerCaps (GDI32.@)
6306 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6308 static int hinting
= -1;
6309 static int subpixel
= -1;
6313 hinting
= is_hinting_enabled();
6314 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6317 if ( subpixel
== -1 )
6319 subpixel
= is_subpixel_rendering_enabled();
6320 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6323 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6324 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6326 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6327 lprs
->nLanguageID
= 0;
6331 /*************************************************************
6332 * WineEngRealizationInfo
6334 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6336 FIXME("(%p, %p): stub!\n", font
, info
);
6339 if(FT_IS_SCALABLE(font
->ft_face
))
6342 info
->cache_num
= font
->cache_num
;
6343 info
->unknown2
= -1;
6347 /*************************************************************************
6348 * Kerning support for TrueType fonts
6350 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6352 struct TT_kern_table
6358 struct TT_kern_subtable
6367 USHORT horizontal
: 1;
6369 USHORT cross_stream
: 1;
6370 USHORT override
: 1;
6371 USHORT reserved1
: 4;
6377 struct TT_format0_kern_subtable
6381 USHORT entrySelector
;
6392 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6393 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6394 const USHORT
*glyph_to_char
,
6395 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6398 const struct TT_kern_pair
*tt_kern_pair
;
6400 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6402 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6404 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6405 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6406 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6408 if (!kern_pair
|| !cPairs
)
6411 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6413 nPairs
= min(nPairs
, cPairs
);
6415 for (i
= 0; i
< nPairs
; i
++)
6417 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6418 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6419 /* this algorithm appears to better match what Windows does */
6420 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6421 if (kern_pair
->iKernAmount
< 0)
6423 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6424 kern_pair
->iKernAmount
-= font
->ppem
;
6426 else if (kern_pair
->iKernAmount
> 0)
6428 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6429 kern_pair
->iKernAmount
+= font
->ppem
;
6431 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6433 TRACE("left %u right %u value %d\n",
6434 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6438 TRACE("copied %u entries\n", nPairs
);
6442 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6446 const struct TT_kern_table
*tt_kern_table
;
6447 const struct TT_kern_subtable
*tt_kern_subtable
;
6449 USHORT
*glyph_to_char
;
6452 EnterCriticalSection( &freetype_cs
);
6453 if (font
->total_kern_pairs
!= (DWORD
)-1)
6455 if (cPairs
&& kern_pair
)
6457 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6458 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6459 LeaveCriticalSection( &freetype_cs
);
6462 LeaveCriticalSection( &freetype_cs
);
6463 return font
->total_kern_pairs
;
6466 font
->total_kern_pairs
= 0;
6468 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6470 if (length
== GDI_ERROR
)
6472 TRACE("no kerning data in the font\n");
6473 LeaveCriticalSection( &freetype_cs
);
6477 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6480 WARN("Out of memory\n");
6481 LeaveCriticalSection( &freetype_cs
);
6485 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6487 /* build a glyph index to char code map */
6488 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6491 WARN("Out of memory allocating a glyph index to char code map\n");
6492 HeapFree(GetProcessHeap(), 0, buf
);
6493 LeaveCriticalSection( &freetype_cs
);
6497 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6503 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6505 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6506 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6510 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6512 /* FIXME: This doesn't match what Windows does: it does some fancy
6513 * things with duplicate glyph index to char code mappings, while
6514 * we just avoid overriding existing entries.
6516 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6517 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6519 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6526 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6527 for (n
= 0; n
<= 65535; n
++)
6528 glyph_to_char
[n
] = (USHORT
)n
;
6531 tt_kern_table
= buf
;
6532 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6533 TRACE("version %u, nTables %u\n",
6534 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6536 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6538 for (i
= 0; i
< nTables
; i
++)
6540 struct TT_kern_subtable tt_kern_subtable_copy
;
6542 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6543 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6544 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6546 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6547 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6548 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6550 /* According to the TrueType specification this is the only format
6551 * that will be properly interpreted by Windows and OS/2
6553 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6555 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6557 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6558 glyph_to_char
, NULL
, 0);
6559 font
->total_kern_pairs
+= new_chunk
;
6561 if (!font
->kern_pairs
)
6562 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6563 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6565 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6566 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6568 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6569 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6572 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6574 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6577 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6578 HeapFree(GetProcessHeap(), 0, buf
);
6580 if (cPairs
&& kern_pair
)
6582 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6583 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6584 LeaveCriticalSection( &freetype_cs
);
6587 LeaveCriticalSection( &freetype_cs
);
6588 return font
->total_kern_pairs
;
6591 #else /* HAVE_FREETYPE */
6593 /*************************************************************************/
6595 BOOL
WineEngInit(void)
6599 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6603 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6608 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6613 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6614 LPWORD pgi
, DWORD flags
)
6619 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6620 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6623 ERR("called but we don't have FreeType\n");
6627 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6629 ERR("called but we don't have FreeType\n");
6633 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6634 OUTLINETEXTMETRICW
*potm
)
6636 ERR("called but we don't have FreeType\n");
6640 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6643 ERR("called but we don't have FreeType\n");
6647 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6650 ERR("called but we don't have FreeType\n");
6654 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
6656 ERR("called but we don't have FreeType\n");
6660 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6663 ERR("called but we don't have FreeType\n");
6667 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6668 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6670 ERR("called but we don't have FreeType\n");
6674 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6675 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6677 ERR("called but we don't have FreeType\n");
6681 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6684 ERR("called but we don't have FreeType\n");
6688 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6690 ERR("called but we don't have FreeType\n");
6694 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6696 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6700 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6702 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6706 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6708 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
6712 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6714 FIXME("(%p, %p, %u): stub\n", font
, fs
, flags
);
6715 return DEFAULT_CHARSET
;
6718 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6723 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6725 FIXME("(%p, %p): stub\n", font
, glyphset
);
6729 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6734 /*************************************************************************
6735 * GetRasterizerCaps (GDI32.@)
6737 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6739 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6741 lprs
->nLanguageID
= 0;
6745 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6747 ERR("called but we don't have FreeType\n");
6751 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6753 ERR("called but we don't have FreeType\n");
6757 #endif /* HAVE_FREETYPE */