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 BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
476 static CRITICAL_SECTION freetype_cs
;
477 static CRITICAL_SECTION_DEBUG critsect_debug
=
480 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
481 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
483 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
485 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
487 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
488 static BOOL use_default_fallback
= FALSE
;
490 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
492 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
493 'W','i','n','d','o','w','s',' ','N','T','\\',
494 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
495 'S','y','s','t','e','m','L','i','n','k',0};
497 /****************************************
498 * Notes on .fon files
500 * The fonts System, FixedSys and Terminal are special. There are typically multiple
501 * versions installed for different resolutions and codepages. Windows stores which one to use
502 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
504 * FIXEDFON.FON FixedSys
506 * OEMFONT.FON Terminal
507 * LogPixels Current dpi set by the display control panel applet
508 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
509 * also has a LogPixels value that appears to mirror this)
511 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
512 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
513 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
514 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
515 * so that makes sense.
517 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
518 * to be mapped into the registry on Windows 2000 at least).
521 * ega80woa.fon=ega80850.fon
522 * ega40woa.fon=ega40850.fon
523 * cga80woa.fon=cga80850.fon
524 * cga40woa.fon=cga40850.fon
527 /* These are all structures needed for the GSUB table */
529 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
530 #define TATEGAKI_LOWER_BOUND 0x02F1
546 GSUB_ScriptRecord ScriptRecord
[1];
552 } GSUB_LangSysRecord
;
557 GSUB_LangSysRecord LangSysRecord
[1];
561 WORD LookupOrder
; /* Reserved */
562 WORD ReqFeatureIndex
;
564 WORD FeatureIndex
[1];
570 } GSUB_FeatureRecord
;
574 GSUB_FeatureRecord FeatureRecord
[1];
578 WORD FeatureParams
; /* Reserved */
580 WORD LookupListIndex
[1];
599 } GSUB_CoverageFormat1
;
604 WORD StartCoverageIndex
;
610 GSUB_RangeRecord RangeRecord
[1];
611 } GSUB_CoverageFormat2
;
614 WORD SubstFormat
; /* = 1 */
617 } GSUB_SingleSubstFormat1
;
620 WORD SubstFormat
; /* = 2 */
624 }GSUB_SingleSubstFormat2
;
626 #ifdef HAVE_CARBON_CARBON_H
627 static char *find_cache_dir(void)
631 static char cached_path
[MAX_PATH
];
632 static const char *wine
= "/Wine", *fonts
= "/Fonts";
634 if(*cached_path
) return cached_path
;
636 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
639 WARN("can't create cached data folder\n");
642 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
645 WARN("can't create cached data path\n");
649 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
651 ERR("Could not create full path\n");
655 strcat(cached_path
, wine
);
657 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
659 WARN("Couldn't mkdir %s\n", cached_path
);
663 strcat(cached_path
, fonts
);
664 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
666 WARN("Couldn't mkdir %s\n", cached_path
);
673 /******************************************************************
676 * Extracts individual TrueType font files from a Mac suitcase font
677 * and saves them into the user's caches directory (see
679 * Returns a NULL terminated array of filenames.
681 * We do this because they are apps that try to read ttf files
682 * themselves and they don't like Mac suitcase files.
684 static char **expand_mac_font(const char *path
)
691 const char *filename
;
695 unsigned int size
, max_size
;
698 TRACE("path %s\n", path
);
700 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
703 WARN("failed to get ref\n");
707 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
710 TRACE("no data fork, so trying resource fork\n");
711 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
714 TRACE("unable to open resource fork\n");
721 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
724 CloseResFile(res_ref
);
728 out_dir
= find_cache_dir();
730 filename
= strrchr(path
, '/');
731 if(!filename
) filename
= path
;
734 /* output filename has the form out_dir/filename_%04x.ttf */
735 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
742 unsigned short *num_faces_ptr
, num_faces
, face
;
745 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
747 fond
= Get1IndResource(fond_res
, idx
);
749 TRACE("got fond resource %d\n", idx
);
752 fam_rec
= *(FamRec
**)fond
;
753 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
754 num_faces
= GET_BE_WORD(*num_faces_ptr
);
756 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
757 TRACE("num faces %04x\n", num_faces
);
758 for(face
= 0; face
< num_faces
; face
++, assoc
++)
761 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
762 unsigned short size
, font_id
;
765 size
= GET_BE_WORD(assoc
->fontSize
);
766 font_id
= GET_BE_WORD(assoc
->fontID
);
769 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
773 TRACE("trying to load sfnt id %04x\n", font_id
);
774 sfnt
= GetResource(sfnt_res
, font_id
);
777 TRACE("can't get sfnt resource %04x\n", font_id
);
781 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
786 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
788 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
789 if(fd
!= -1 || errno
== EEXIST
)
793 unsigned char *sfnt_data
;
796 sfnt_data
= *(unsigned char**)sfnt
;
797 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
801 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
804 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
806 ret
.array
[ret
.size
++] = output
;
810 WARN("unable to create %s\n", output
);
811 HeapFree(GetProcessHeap(), 0, output
);
814 ReleaseResource(sfnt
);
817 ReleaseResource(fond
);
820 CloseResFile(res_ref
);
825 #endif /* HAVE_CARBON_CARBON_H */
827 static inline BOOL
is_win9x(void)
829 return GetVersion() & 0x80000000;
832 This function builds an FT_Fixed from a double. It fails if the absolute
833 value of the float number is greater than 32768.
835 static inline FT_Fixed
FT_FixedFromFloat(double f
)
841 This function builds an FT_Fixed from a FIXED. It simply put f.value
842 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
844 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
846 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
850 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
855 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
856 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
858 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
859 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
861 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
863 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
865 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
869 file
= strrchr(face
->file
, '/');
874 if(!strcasecmp(file
, file_nameA
))
876 HeapFree(GetProcessHeap(), 0, file_nameA
);
881 HeapFree(GetProcessHeap(), 0, file_nameA
);
885 static Family
*find_family_from_name(const WCHAR
*name
)
889 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
891 if(!strcmpiW(family
->FamilyName
, name
))
898 static void DumpSubstList(void)
902 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
904 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
905 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
906 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
908 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
909 debugstr_w(psub
->to
.name
));
914 static LPWSTR
strdupW(LPCWSTR p
)
917 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
918 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
923 static LPSTR
strdupA(LPCSTR p
)
926 DWORD len
= (strlen(p
) + 1);
927 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
932 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
937 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
939 if(!strcmpiW(element
->from
.name
, from_name
) &&
940 (element
->from
.charset
== from_charset
||
941 element
->from
.charset
== -1))
948 #define ADD_FONT_SUBST_FORCE 1
950 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
952 FontSubst
*from_exist
, *to_exist
;
954 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
956 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
958 list_remove(&from_exist
->entry
);
959 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
960 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
961 HeapFree(GetProcessHeap(), 0, from_exist
);
967 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
971 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
972 subst
->to
.name
= strdupW(to_exist
->to
.name
);
975 list_add_tail(subst_list
, &subst
->entry
);
980 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
981 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
982 HeapFree(GetProcessHeap(), 0, subst
);
986 static void split_subst_info(NameCs
*nc
, LPSTR str
)
988 CHAR
*p
= strrchr(str
, ',');
993 nc
->charset
= strtol(p
+1, NULL
, 10);
996 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
997 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
998 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
1001 static void LoadSubstList(void)
1005 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1009 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1010 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1011 &hkey
) == ERROR_SUCCESS
) {
1013 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1014 &valuelen
, &datalen
, NULL
, NULL
);
1016 valuelen
++; /* returned value doesn't include room for '\0' */
1017 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1018 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1022 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1023 &dlen
) == ERROR_SUCCESS
) {
1024 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1026 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1027 split_subst_info(&psub
->from
, value
);
1028 split_subst_info(&psub
->to
, data
);
1030 /* Win 2000 doesn't allow mapping between different charsets
1031 or mapping of DEFAULT_CHARSET */
1032 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1033 psub
->to
.charset
== DEFAULT_CHARSET
) {
1034 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1035 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1036 HeapFree(GetProcessHeap(), 0, psub
);
1038 add_font_subst(&font_subst_list
, psub
, 0);
1040 /* reset dlen and vlen */
1044 HeapFree(GetProcessHeap(), 0, data
);
1045 HeapFree(GetProcessHeap(), 0, value
);
1051 /*****************************************************************
1052 * get_name_table_entry
1054 * Supply the platform, encoding, language and name ids in req
1055 * and if the name exists the function will fill in the string
1056 * and string_len members. The string is owned by FreeType so
1057 * don't free it. Returns TRUE if the name is found else FALSE.
1059 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1062 FT_UInt num_names
, name_index
;
1064 if(FT_IS_SFNT(ft_face
))
1066 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1068 for(name_index
= 0; name_index
< num_names
; name_index
++)
1070 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1072 if((name
.platform_id
== req
->platform_id
) &&
1073 (name
.encoding_id
== req
->encoding_id
) &&
1074 (name
.language_id
== req
->language_id
) &&
1075 (name
.name_id
== req
->name_id
))
1077 req
->string
= name
.string
;
1078 req
->string_len
= name
.string_len
;
1085 req
->string_len
= 0;
1089 static WCHAR
*get_familyname(FT_Face ft_face
)
1091 WCHAR
*family
= NULL
;
1094 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1095 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1096 name
.language_id
= GetUserDefaultLCID();
1097 name
.name_id
= TT_NAME_ID_FONT_FAMILY
;
1099 if(get_name_table_entry(ft_face
, &name
))
1103 /* String is not nul terminated and string_len is a byte length. */
1104 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1105 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1107 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1108 family
[i
] = GET_BE_WORD(*tmp
);
1111 TRACE("Got localised name %s\n", debugstr_w(family
));
1118 /*****************************************************************
1121 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1122 * of FreeType that don't export this function.
1125 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1130 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1131 if(pFT_Load_Sfnt_Table
)
1133 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1135 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1136 else /* Do it the hard way */
1138 TT_Face tt_face
= (TT_Face
) ft_face
;
1139 SFNT_Interface
*sfnt
;
1140 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1143 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1147 /* A field was added in the middle of the structure in 2.1.x */
1148 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1150 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1158 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1159 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1160 "Please upgrade your freetype library.\n");
1163 err
= FT_Err_Unimplemented_Feature
;
1169 static inline int TestStyles(DWORD flags
, DWORD styles
)
1171 return (flags
& styles
) == styles
;
1174 static int StyleOrdering(Face
*face
)
1176 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1178 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1180 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1182 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1185 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1186 debugstr_w(face
->family
->FamilyName
),
1187 debugstr_w(face
->StyleName
),
1193 /* Add a style of face to a font family using an ordering of the list such
1194 that regular fonts come before bold and italic, and single styles come
1195 before compound styles. */
1196 static void AddFaceToFamily(Face
*face
, Family
*family
)
1200 LIST_FOR_EACH( entry
, &family
->faces
)
1202 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1203 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1205 list_add_before( entry
, &face
->entry
);
1208 #define ADDFONT_EXTERNAL_FONT 0x01
1209 #define ADDFONT_FORCE_BITMAP 0x02
1210 #define ADDFONT_HIDDEN 0x04
1211 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1212 char *fake_family
, const WCHAR
*target_family
, DWORD flags
, Face
**face_to_return
)
1216 TT_Header
*pHeader
= NULL
;
1217 WCHAR
*english_family
, *localised_family
, *StyleW
;
1219 Family
*family
= NULL
;
1220 Face
*face
, *first_face
= NULL
;
1221 struct list
*family_elem_ptr
, *face_elem_ptr
;
1223 FT_Long face_index
= 0, num_faces
;
1224 #ifdef HAVE_FREETYPE_FTWINFNT_H
1225 FT_WinFNT_HeaderRec winfnt_header
;
1227 int i
, bitmap_num
, internal_leading
;
1230 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1231 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1233 #ifdef HAVE_CARBON_CARBON_H
1234 if(file
&& !fake_family
)
1236 char **mac_list
= expand_mac_font(file
);
1239 BOOL had_one
= FALSE
;
1241 for(cursor
= mac_list
; *cursor
; cursor
++)
1244 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
, face_to_return
);
1245 HeapFree(GetProcessHeap(), 0, *cursor
);
1247 HeapFree(GetProcessHeap(), 0, mac_list
);
1252 #endif /* HAVE_CARBON_CARBON_H */
1255 char *family_name
= fake_family
;
1259 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1260 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1263 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1264 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1268 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1272 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*/
1273 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1274 pFT_Done_Face(ft_face
);
1278 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1279 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1280 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1281 pFT_Done_Face(ft_face
);
1285 if(FT_IS_SFNT(ft_face
))
1287 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1288 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1289 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1291 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1292 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1293 pFT_Done_Face(ft_face
);
1297 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1298 we don't want to load these. */
1299 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1303 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1305 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1306 pFT_Done_Face(ft_face
);
1312 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1313 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1314 pFT_Done_Face(ft_face
);
1318 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1320 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1321 pFT_Done_Face(ft_face
);
1327 localised_family
= get_familyname(ft_face
);
1328 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1330 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1331 HeapFree(GetProcessHeap(), 0, localised_family
);
1332 num_faces
= ft_face
->num_faces
;
1333 pFT_Done_Face(ft_face
);
1336 HeapFree(GetProcessHeap(), 0, localised_family
);
1340 family_name
= ft_face
->family_name
;
1344 My_FT_Bitmap_Size
*size
= NULL
;
1347 if(!FT_IS_SCALABLE(ft_face
))
1348 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1350 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1351 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1352 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1354 internal_leading
= 0;
1355 memset(&fs
, 0, sizeof(fs
));
1357 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1359 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1360 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1361 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1362 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1363 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1364 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1365 if(pOS2
->version
== 0) {
1368 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1369 fs
.fsCsb
[0] |= FS_LATIN1
;
1371 fs
.fsCsb
[0] |= FS_SYMBOL
;
1374 #ifdef HAVE_FREETYPE_FTWINFNT_H
1375 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1377 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1378 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1379 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1381 internal_leading
= winfnt_header
.internal_leading
;
1385 if (!(flags
& ADDFONT_HIDDEN
))
1387 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1388 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1389 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1391 localised_family
= NULL
;
1394 localised_family
= get_familyname(ft_face
);
1395 if (localised_family
&& !strcmpiW(localised_family
, english_family
))
1397 HeapFree(GetProcessHeap(), 0, localised_family
);
1398 localised_family
= NULL
;
1403 LIST_FOR_EACH(family_elem_ptr
, &font_list
)
1405 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1406 if(!strcmpiW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1412 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1413 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1414 list_init(&family
->faces
);
1415 list_add_tail(&font_list
, &family
->entry
);
1417 if (localised_family
)
1419 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1420 subst
->from
.name
= strdupW(english_family
);
1421 subst
->from
.charset
= -1;
1422 subst
->to
.name
= strdupW(localised_family
);
1423 subst
->to
.charset
= -1;
1424 add_font_subst(&font_subst_list
, subst
, 0);
1427 HeapFree(GetProcessHeap(), 0, localised_family
);
1428 HeapFree(GetProcessHeap(), 0, english_family
);
1430 face_elem_ptr
= list_head(&family
->faces
);
1431 while(face_elem_ptr
)
1433 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1434 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1435 if (!strcmpiW(face
->StyleName
, StyleW
) &&
1436 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) )))
1438 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1439 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1440 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1444 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1445 HeapFree(GetProcessHeap(), 0, StyleW
);
1446 pFT_Done_Face(ft_face
);
1449 if (!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
)
1451 TRACE("Original font is newer so skipping this one\n");
1452 HeapFree(GetProcessHeap(), 0, StyleW
);
1453 pFT_Done_Face(ft_face
);
1458 TRACE("Replacing original with this one\n");
1459 list_remove(&face
->entry
);
1460 HeapFree(GetProcessHeap(), 0, face
->file
);
1461 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1462 HeapFree(GetProcessHeap(), 0, face
);
1469 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1470 face
->cached_enum_data
= NULL
;
1471 face
->StyleName
= StyleW
;
1474 face
->file
= strdupA(file
);
1475 face
->font_data_ptr
= NULL
;
1476 face
->font_data_size
= 0;
1481 face
->font_data_ptr
= font_data_ptr
;
1482 face
->font_data_size
= font_data_size
;
1484 face
->face_index
= face_index
;
1486 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1487 face
->ntmFlags
|= NTM_ITALIC
;
1488 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1489 face
->ntmFlags
|= NTM_BOLD
;
1490 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1491 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1492 face
->family
= family
;
1493 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1495 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1497 if(FT_IS_SCALABLE(ft_face
)) {
1498 memset(&face
->size
, 0, sizeof(face
->size
));
1499 face
->scalable
= TRUE
;
1501 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1502 size
->height
, size
->width
, size
->size
>> 6,
1503 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1504 face
->size
.height
= size
->height
;
1505 face
->size
.width
= size
->width
;
1506 face
->size
.size
= size
->size
;
1507 face
->size
.x_ppem
= size
->x_ppem
;
1508 face
->size
.y_ppem
= size
->y_ppem
;
1509 face
->size
.internal_leading
= internal_leading
;
1510 face
->scalable
= FALSE
;
1513 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1515 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1517 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1518 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1521 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1522 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1523 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1524 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1527 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1528 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1529 switch(ft_face
->charmaps
[i
]->encoding
) {
1530 case FT_ENCODING_UNICODE
:
1531 case FT_ENCODING_APPLE_ROMAN
:
1532 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1534 case FT_ENCODING_MS_SYMBOL
:
1535 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1543 if (!(flags
& ADDFONT_HIDDEN
))
1545 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1546 have_installed_roman_font
= TRUE
;
1548 AddFaceToFamily(face
, family
);
1551 if (!first_face
) first_face
= face
;
1552 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1554 num_faces
= ft_face
->num_faces
;
1555 pFT_Done_Face(ft_face
);
1556 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1557 debugstr_w(StyleW
));
1558 } while(num_faces
> ++face_index
);
1560 if (face_to_return
) *face_to_return
= first_face
;
1565 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
, Face
**face_to_return
)
1567 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
, face_to_return
);
1570 static void DumpFontList(void)
1574 struct list
*family_elem_ptr
, *face_elem_ptr
;
1576 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1577 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1578 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1579 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1580 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1581 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1583 TRACE(" %d", face
->size
.height
);
1590 /***********************************************************
1591 * The replacement list is a way to map an entire font
1592 * family onto another family. For example adding
1594 * [HKCU\Software\Wine\Fonts\Replacements]
1595 * "Wingdings"="Winedings"
1597 * would enumerate the Winedings font both as Winedings and
1598 * Wingdings. However if a real Wingdings font is present the
1599 * replacement does not take place.
1602 static void LoadReplaceList(void)
1605 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1610 struct list
*family_elem_ptr
, *face_elem_ptr
;
1613 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1614 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1616 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1617 &valuelen
, &datalen
, NULL
, NULL
);
1619 valuelen
++; /* returned value doesn't include room for '\0' */
1620 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1621 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1625 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1626 &dlen
) == ERROR_SUCCESS
) {
1627 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1628 /* "NewName"="Oldname" */
1629 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1631 /* Find the old family and hence all of the font files
1633 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1634 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1635 if(!strcmpiW(family
->FamilyName
, data
)) {
1636 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1637 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1638 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1639 debugstr_w(face
->StyleName
), familyA
);
1640 /* Now add a new entry with the new family name */
1641 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0), NULL
);
1646 /* reset dlen and vlen */
1650 HeapFree(GetProcessHeap(), 0, data
);
1651 HeapFree(GetProcessHeap(), 0, value
);
1656 /*************************************************************
1659 static BOOL
init_system_links(void)
1663 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1664 WCHAR
*value
, *data
;
1665 WCHAR
*entry
, *next
;
1666 SYSTEM_LINKS
*font_link
, *system_font_link
;
1667 CHILD_FONT
*child_font
;
1668 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1669 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1675 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1677 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1678 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1679 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1680 val_len
= max_val
+ 1;
1681 data_len
= max_data
;
1683 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1685 memset(&fs
, 0, sizeof(fs
));
1686 psub
= get_font_subst(&font_subst_list
, value
, -1);
1687 /* Don't store fonts that are only substitutes for other fonts */
1690 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1693 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1694 font_link
->font_name
= strdupW(value
);
1695 list_init(&font_link
->links
);
1696 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1699 CHILD_FONT
*child_font
;
1701 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1703 next
= entry
+ strlenW(entry
) + 1;
1705 face_name
= strchrW(entry
, ',');
1709 while(isspaceW(*face_name
))
1712 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1714 face_name
= psub
->to
.name
;
1716 face
= find_face_from_filename(entry
, face_name
);
1719 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1723 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1724 child_font
->face
= face
;
1725 child_font
->font
= NULL
;
1726 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1727 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1728 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1729 list_add_tail(&font_link
->links
, &child_font
->entry
);
1731 family
= find_family_from_name(font_link
->font_name
);
1734 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1736 face
->fs_links
= fs
;
1739 list_add_tail(&system_links
, &font_link
->entry
);
1741 val_len
= max_val
+ 1;
1742 data_len
= max_data
;
1745 HeapFree(GetProcessHeap(), 0, value
);
1746 HeapFree(GetProcessHeap(), 0, data
);
1750 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1753 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1754 system_font_link
->font_name
= strdupW(System
);
1755 list_init(&system_font_link
->links
);
1757 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1760 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1761 child_font
->face
= face
;
1762 child_font
->font
= NULL
;
1763 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1764 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1766 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1768 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1770 CHILD_FONT
*font_link_entry
;
1771 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1773 CHILD_FONT
*new_child
;
1774 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1775 new_child
->face
= font_link_entry
->face
;
1776 new_child
->font
= NULL
;
1777 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1782 list_add_tail(&system_links
, &system_font_link
->entry
);
1786 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1789 struct dirent
*dent
;
1790 char path
[MAX_PATH
];
1792 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1794 dir
= opendir(dirname
);
1796 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1799 while((dent
= readdir(dir
)) != NULL
) {
1800 struct stat statbuf
;
1802 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1805 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1807 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1809 if(stat(path
, &statbuf
) == -1)
1811 WARN("Can't stat %s\n", debugstr_a(path
));
1814 if(S_ISDIR(statbuf
.st_mode
))
1815 ReadFontDir(path
, external_fonts
);
1817 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0, NULL
);
1823 static void load_fontconfig_fonts(void)
1825 #ifdef SONAME_LIBFONTCONFIG
1826 void *fc_handle
= NULL
;
1835 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1837 TRACE("Wine cannot find the fontconfig library (%s).\n",
1838 SONAME_LIBFONTCONFIG
);
1841 #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;}
1842 LOAD_FUNCPTR(FcConfigGetCurrent
);
1843 LOAD_FUNCPTR(FcFontList
);
1844 LOAD_FUNCPTR(FcFontSetDestroy
);
1845 LOAD_FUNCPTR(FcInit
);
1846 LOAD_FUNCPTR(FcObjectSetAdd
);
1847 LOAD_FUNCPTR(FcObjectSetCreate
);
1848 LOAD_FUNCPTR(FcObjectSetDestroy
);
1849 LOAD_FUNCPTR(FcPatternCreate
);
1850 LOAD_FUNCPTR(FcPatternDestroy
);
1851 LOAD_FUNCPTR(FcPatternGetBool
);
1852 LOAD_FUNCPTR(FcPatternGetString
);
1855 if(!pFcInit()) return;
1857 config
= pFcConfigGetCurrent();
1858 pat
= pFcPatternCreate();
1859 os
= pFcObjectSetCreate();
1860 pFcObjectSetAdd(os
, FC_FILE
);
1861 pFcObjectSetAdd(os
, FC_SCALABLE
);
1862 fontset
= pFcFontList(config
, pat
, os
);
1863 if(!fontset
) return;
1864 for(i
= 0; i
< fontset
->nfont
; i
++) {
1867 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1869 TRACE("fontconfig: %s\n", file
);
1871 /* We're just interested in OT/TT fonts for now, so this hack just
1872 picks up the scalable fonts without extensions .pf[ab] to save time
1873 loading every other font */
1875 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1877 TRACE("not scalable\n");
1881 len
= strlen( file
);
1882 if(len
< 4) continue;
1883 ext
= &file
[ len
- 3 ];
1884 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1885 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
, NULL
);
1887 pFcFontSetDestroy(fontset
);
1888 pFcObjectSetDestroy(os
);
1889 pFcPatternDestroy(pat
);
1895 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1898 const char *data_dir
= wine_get_data_dir();
1900 if (!data_dir
) data_dir
= wine_get_build_dir();
1907 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1909 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1911 strcpy(unix_name
, data_dir
);
1912 strcat(unix_name
, "/fonts/");
1914 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1916 EnterCriticalSection( &freetype_cs
);
1917 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
, NULL
);
1918 LeaveCriticalSection( &freetype_cs
);
1919 HeapFree(GetProcessHeap(), 0, unix_name
);
1924 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1926 static const WCHAR slashW
[] = {'\\','\0'};
1928 WCHAR windowsdir
[MAX_PATH
];
1931 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1932 strcatW(windowsdir
, fontsW
);
1933 strcatW(windowsdir
, slashW
);
1934 strcatW(windowsdir
, file
);
1935 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1936 EnterCriticalSection( &freetype_cs
);
1937 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
, NULL
);
1938 LeaveCriticalSection( &freetype_cs
);
1939 HeapFree(GetProcessHeap(), 0, unixname
);
1944 static void load_system_fonts(void)
1947 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1948 const WCHAR
* const *value
;
1950 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1953 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1954 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1955 strcatW(windowsdir
, fontsW
);
1956 for(value
= SystemFontValues
; *value
; value
++) {
1957 dlen
= sizeof(data
);
1958 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1962 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1963 if((unixname
= wine_get_unix_file_name(pathW
))) {
1964 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
, NULL
);
1965 HeapFree(GetProcessHeap(), 0, unixname
);
1968 load_font_from_data_dir(data
);
1975 /*************************************************************
1977 * This adds registry entries for any externally loaded fonts
1978 * (fonts from fontconfig or FontDirs). It also deletes entries
1979 * of no longer existing fonts.
1982 static void update_reg_entries(void)
1984 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1989 struct list
*family_elem_ptr
, *face_elem_ptr
;
1991 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1992 static const WCHAR spaceW
[] = {' ', '\0'};
1995 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1996 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1997 ERR("Can't create Windows font reg key\n");
2001 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2002 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2003 ERR("Can't create Windows font reg key\n");
2007 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2008 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2009 ERR("Can't create external font reg key\n");
2013 /* enumerate the fonts and add external ones to the two keys */
2015 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2016 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2017 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2018 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2019 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2020 if(!face
->external
) continue;
2022 if (!(face
->ntmFlags
& NTM_REGULAR
))
2023 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2024 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2025 strcpyW(valueW
, family
->FamilyName
);
2026 if(len
!= len_fam
) {
2027 strcatW(valueW
, spaceW
);
2028 strcatW(valueW
, face
->StyleName
);
2030 strcatW(valueW
, TrueType
);
2032 file
= wine_get_dos_file_name(face
->file
);
2034 len
= strlenW(file
) + 1;
2037 if((path
= strrchr(face
->file
, '/')) == NULL
)
2041 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2043 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2044 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2046 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2047 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2048 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2050 HeapFree(GetProcessHeap(), 0, file
);
2051 HeapFree(GetProcessHeap(), 0, valueW
);
2055 if(external_key
) RegCloseKey(external_key
);
2056 if(win9x_key
) RegCloseKey(win9x_key
);
2057 if(winnt_key
) RegCloseKey(winnt_key
);
2061 static void delete_external_font_keys(void)
2063 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2064 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2068 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2069 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2070 ERR("Can't create Windows font reg key\n");
2074 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2075 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2076 ERR("Can't create Windows font reg key\n");
2080 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2081 ERR("Can't create external font reg key\n");
2085 /* Delete all external fonts added last time */
2087 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2088 &valuelen
, &datalen
, NULL
, NULL
);
2089 valuelen
++; /* returned value doesn't include room for '\0' */
2090 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2091 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2093 dlen
= datalen
* sizeof(WCHAR
);
2096 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2097 &dlen
) == ERROR_SUCCESS
) {
2099 RegDeleteValueW(winnt_key
, valueW
);
2100 RegDeleteValueW(win9x_key
, valueW
);
2101 /* reset dlen and vlen */
2105 HeapFree(GetProcessHeap(), 0, data
);
2106 HeapFree(GetProcessHeap(), 0, valueW
);
2108 /* Delete the old external fonts key */
2109 RegCloseKey(external_key
);
2110 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2113 if(win9x_key
) RegCloseKey(win9x_key
);
2114 if(winnt_key
) RegCloseKey(winnt_key
);
2117 /*************************************************************
2118 * WineEngAddFontResourceEx
2121 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2127 if (ft_handle
) /* do it only if we have freetype up and running */
2132 FIXME("Ignoring flags %x\n", flags
);
2134 if((unixname
= wine_get_unix_file_name(file
)))
2136 EnterCriticalSection( &freetype_cs
);
2137 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
, NULL
);
2138 LeaveCriticalSection( &freetype_cs
);
2139 HeapFree(GetProcessHeap(), 0, unixname
);
2141 if (!ret
&& !strchrW(file
, '\\')) {
2142 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2143 ret
= load_font_from_winfonts_dir(file
);
2145 /* Try in datadir/fonts (or builddir/fonts),
2146 * needed for Magic the Gathering Online
2148 ret
= load_font_from_data_dir(file
);
2155 /*************************************************************
2156 * WineEngAddFontMemResourceEx
2159 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2163 if (ft_handle
) /* do it only if we have freetype up and running */
2165 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2167 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2168 memcpy(pFontCopy
, pbFont
, cbFont
);
2170 EnterCriticalSection( &freetype_cs
);
2171 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
, NULL
);
2172 LeaveCriticalSection( &freetype_cs
);
2176 TRACE("AddFontToList failed\n");
2177 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2180 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2181 * For now return something unique but quite random
2183 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2184 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2191 /*************************************************************
2192 * WineEngRemoveFontResourceEx
2195 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2198 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2202 static const struct nls_update_font_list
2204 UINT ansi_cp
, oem_cp
;
2205 const char *oem
, *fixed
, *system
;
2206 const char *courier
, *serif
, *small
, *sserif
;
2207 /* these are for font substitutes */
2208 const char *shelldlg
, *tmsrmn
;
2209 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2213 const char *from
, *to
;
2214 } arial_0
, courier_new_0
, times_new_roman_0
;
2215 } nls_update_font_list
[] =
2217 /* Latin 1 (United States) */
2218 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2219 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2220 "Tahoma","Times New Roman",
2221 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2224 /* Latin 1 (Multilingual) */
2225 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2226 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2231 /* Eastern Europe */
2232 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2233 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2234 "Tahoma","Times New Roman", /* FIXME unverified */
2235 "Fixedsys,238", "System,238",
2236 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2237 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2238 { "Arial CE,0", "Arial,238" },
2239 { "Courier New CE,0", "Courier New,238" },
2240 { "Times New Roman CE,0", "Times New Roman,238" }
2243 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2244 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,204", "System,204",
2247 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2248 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2249 { "Arial Cyr,0", "Arial,204" },
2250 { "Courier New Cyr,0", "Courier New,204" },
2251 { "Times New Roman Cyr,0", "Times New Roman,204" }
2254 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2255 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 "Fixedsys,161", "System,161",
2258 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2259 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2260 { "Arial Greek,0", "Arial,161" },
2261 { "Courier New Greek,0", "Courier New,161" },
2262 { "Times New Roman Greek,0", "Times New Roman,161" }
2265 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2266 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2267 "Tahoma","Times New Roman", /* FIXME unverified */
2268 "Fixedsys,162", "System,162",
2269 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2270 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2271 { "Arial Tur,0", "Arial,162" },
2272 { "Courier New Tur,0", "Courier New,162" },
2273 { "Times New Roman Tur,0", "Times New Roman,162" }
2276 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2277 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 "Fixedsys,177", "System,177",
2280 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2281 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2285 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2286 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2287 "Tahoma","Times New Roman", /* FIXME unverified */
2288 "Fixedsys,178", "System,178",
2289 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2290 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2294 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2295 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2296 "Tahoma","Times New Roman", /* FIXME unverified */
2297 "Fixedsys,186", "System,186",
2298 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2299 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2300 { "Arial Baltic,0", "Arial,186" },
2301 { "Courier New Baltic,0", "Courier New,186" },
2302 { "Times New Roman Baltic,0", "Times New Roman,186" }
2305 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2306 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2307 "Tahoma","Times New Roman", /* FIXME unverified */
2308 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2312 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2313 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2314 "Tahoma","Times New Roman", /* FIXME unverified */
2315 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2319 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2320 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2321 "MS UI Gothic","MS Serif",
2322 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2325 /* Chinese Simplified */
2326 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2327 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2328 "SimSun", "NSimSun",
2329 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2333 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2334 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2336 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2339 /* Chinese Traditional */
2340 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2341 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2342 "PMingLiU", "MingLiU",
2343 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2348 static const WCHAR
*font_links_list
[] =
2350 Lucida_Sans_Unicode
,
2351 Microsoft_Sans_Serif
,
2355 static const struct font_links_defaults_list
2357 /* Keyed off substitution for "MS Shell Dlg" */
2358 const WCHAR
*shelldlg
;
2359 /* Maximum of four substitutes, plus terminating NULL pointer */
2360 const WCHAR
*substitutes
[5];
2361 } font_links_defaults_list
[] =
2363 /* Non East-Asian */
2364 { Tahoma
, /* FIXME unverified ordering */
2365 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2367 /* Below lists are courtesy of
2368 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2372 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2374 /* Chinese Simplified */
2376 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2380 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2382 /* Chinese Traditional */
2384 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2388 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2390 return ( ansi_cp
== 932 /* CP932 for Japanese */
2391 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2392 || ansi_cp
== 949 /* CP949 for Korean */
2393 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2396 static inline HKEY
create_fonts_NT_registry_key(void)
2400 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2401 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2405 static inline HKEY
create_fonts_9x_registry_key(void)
2409 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2410 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2414 static inline HKEY
create_config_fonts_registry_key(void)
2418 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2419 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2423 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2425 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2426 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2427 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2428 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2431 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2434 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2436 RegDeleteValueA(hkey
, name
);
2439 static void update_font_info(void)
2441 char buf
[40], cpbuf
[40];
2444 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2447 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2450 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2451 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2452 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2453 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2454 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2456 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2457 if (is_dbcs_ansi_cp(ansi_cp
))
2458 use_default_fallback
= TRUE
;
2461 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2463 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2468 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2470 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2472 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2475 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2479 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2480 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2482 hkey
= create_config_fonts_registry_key();
2483 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2484 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2485 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2488 hkey
= create_fonts_NT_registry_key();
2489 add_font_list(hkey
, &nls_update_font_list
[i
]);
2492 hkey
= create_fonts_9x_registry_key();
2493 add_font_list(hkey
, &nls_update_font_list
[i
]);
2496 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2498 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2499 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2500 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2501 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2503 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2504 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2505 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2506 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2507 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2508 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2509 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2510 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2512 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2513 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2514 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2522 /* Delete the FontSubstitutes from other locales */
2523 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2525 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2526 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2527 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2533 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2535 /* Clear out system links */
2536 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, system_link
);
2539 static void populate_system_links(HKEY hkey
, const WCHAR
*name
, const WCHAR
*const *values
)
2549 WCHAR buff
[MAX_PATH
];
2553 static const WCHAR comma
[] = {',',0};
2555 RegDeleteValueW(hkey
, name
);
2560 for (i
= 0; values
[i
] != NULL
; i
++)
2563 if (!strcmpiW(name
,value
))
2565 psub
= get_font_subst(&font_subst_list
, value
, -1);
2567 value
= psub
->to
.name
;
2568 family
= find_family_from_name(value
);
2572 /* Use first extant filename for this Family */
2573 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2577 file
= strrchr(face
->file
, '/');
2586 fileLen
= MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, NULL
, 0);
2587 fileW
= HeapAlloc(GetProcessHeap(), 0, fileLen
* sizeof(WCHAR
));
2588 MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, fileW
, fileLen
);
2589 entryLen
= strlenW(fileW
) + 1 + strlenW(value
) + 1;
2590 if (sizeof(buff
)-(data
-buff
) < entryLen
+ 1)
2592 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name
));
2593 HeapFree(GetProcessHeap(), 0, fileW
);
2596 strcpyW(data
, fileW
);
2597 strcatW(data
, comma
);
2598 strcatW(data
, value
);
2600 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2601 HeapFree(GetProcessHeap(), 0, fileW
);
2607 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (BYTE
*)buff
, (data
-buff
) * sizeof(WCHAR
));
2609 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name
));
2611 TRACE("removed SystemLink for %s\n", debugstr_w(name
));
2614 static void update_system_links(void)
2622 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2624 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE
, system_link
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, &disposition
))
2626 if (disposition
== REG_OPENED_EXISTING_KEY
)
2628 TRACE("SystemLink key already exists, doing nothing\n");
2633 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2635 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2640 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2642 if (!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
))
2644 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2645 populate_system_links(hkey
, font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2647 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2648 populate_system_links(hkey
, psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2651 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2653 populate_system_links(hkey
, font_links_defaults_list
[i
].substitutes
[0], NULL
);
2658 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub
->to
.name
));
2660 WARN("failed to create SystemLink key\n");
2664 static BOOL
init_freetype(void)
2666 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2669 "Wine cannot find the FreeType font library. To enable Wine to\n"
2670 "use TrueType fonts please install a version of FreeType greater than\n"
2671 "or equal to 2.0.5.\n"
2672 "http://www.freetype.org\n");
2676 #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;}
2678 LOAD_FUNCPTR(FT_Vector_Unit
)
2679 LOAD_FUNCPTR(FT_Done_Face
)
2680 LOAD_FUNCPTR(FT_Get_Char_Index
)
2681 LOAD_FUNCPTR(FT_Get_Module
)
2682 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2683 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2684 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2685 LOAD_FUNCPTR(FT_Init_FreeType
)
2686 LOAD_FUNCPTR(FT_Load_Glyph
)
2687 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2688 #ifndef FT_MULFIX_INLINED
2689 LOAD_FUNCPTR(FT_MulFix
)
2691 LOAD_FUNCPTR(FT_New_Face
)
2692 LOAD_FUNCPTR(FT_New_Memory_Face
)
2693 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2694 LOAD_FUNCPTR(FT_Outline_Transform
)
2695 LOAD_FUNCPTR(FT_Outline_Translate
)
2696 LOAD_FUNCPTR(FT_Select_Charmap
)
2697 LOAD_FUNCPTR(FT_Set_Charmap
)
2698 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2699 LOAD_FUNCPTR(FT_Vector_Transform
)
2700 LOAD_FUNCPTR(FT_Render_Glyph
)
2703 /* Don't warn if these ones are missing */
2704 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2705 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2706 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2707 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2708 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2709 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2710 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2712 #ifdef HAVE_FREETYPE_FTWINFNT_H
2713 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2715 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2716 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2717 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2718 <= 2.0.3 has FT_Sqrt64 */
2722 if(pFT_Init_FreeType(&library
) != 0) {
2723 ERR("Can't init FreeType library\n");
2724 wine_dlclose(ft_handle
, NULL
, 0);
2728 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2729 if (pFT_Library_Version
)
2730 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2732 if (FT_Version
.major
<=0)
2738 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2739 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2740 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2741 ((FT_Version
.patch
) & 0x0000ff);
2747 "Wine cannot find certain functions that it needs inside the FreeType\n"
2748 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2749 "FreeType to at least version 2.0.5.\n"
2750 "http://www.freetype.org\n");
2751 wine_dlclose(ft_handle
, NULL
, 0);
2756 /*************************************************************
2759 * Initialize FreeType library and create a list of available faces
2761 BOOL
WineEngInit(void)
2763 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2764 static const WCHAR pathW
[] = {'P','a','t','h',0};
2766 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2767 WCHAR windowsdir
[MAX_PATH
];
2770 const char *data_dir
;
2774 /* update locale dependent font info in registry */
2777 if(!init_freetype()) return FALSE
;
2779 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2780 ERR("Failed to create font mutex\n");
2783 WaitForSingleObject(font_mutex
, INFINITE
);
2785 delete_external_font_keys();
2787 /* load the system bitmap fonts */
2788 load_system_fonts();
2790 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2791 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2792 strcatW(windowsdir
, fontsW
);
2793 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2795 ReadFontDir(unixname
, FALSE
);
2796 HeapFree(GetProcessHeap(), 0, unixname
);
2799 /* load the system truetype fonts */
2800 data_dir
= wine_get_data_dir();
2801 if (!data_dir
) data_dir
= wine_get_build_dir();
2802 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2803 strcpy(unixname
, data_dir
);
2804 strcat(unixname
, "/fonts/");
2805 ReadFontDir(unixname
, TRUE
);
2806 HeapFree(GetProcessHeap(), 0, unixname
);
2809 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2810 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2811 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2813 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2814 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2815 &hkey
) == ERROR_SUCCESS
) {
2816 LPWSTR data
, valueW
;
2817 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2818 &valuelen
, &datalen
, NULL
, NULL
);
2820 valuelen
++; /* returned value doesn't include room for '\0' */
2821 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2822 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2825 dlen
= datalen
* sizeof(WCHAR
);
2827 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
2828 &dlen
) == ERROR_SUCCESS
) {
2829 if(data
[0] && (data
[1] == ':'))
2831 if((unixname
= wine_get_unix_file_name(data
)))
2833 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
, NULL
);
2834 HeapFree(GetProcessHeap(), 0, unixname
);
2837 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
2839 WCHAR pathW
[MAX_PATH
];
2840 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2843 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2844 if((unixname
= wine_get_unix_file_name(pathW
)))
2846 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
, NULL
);
2847 HeapFree(GetProcessHeap(), 0, unixname
);
2850 load_font_from_data_dir(data
);
2852 /* reset dlen and vlen */
2857 HeapFree(GetProcessHeap(), 0, data
);
2858 HeapFree(GetProcessHeap(), 0, valueW
);
2862 load_fontconfig_fonts();
2864 /* then look in any directories that we've specified in the config file */
2865 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2866 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2872 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2874 len
+= sizeof(WCHAR
);
2875 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2876 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2878 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2879 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2880 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2881 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2885 LPSTR next
= strchr( ptr
, ':' );
2886 if (next
) *next
++ = 0;
2887 ReadFontDir( ptr
, TRUE
);
2890 HeapFree( GetProcessHeap(), 0, valueA
);
2892 HeapFree( GetProcessHeap(), 0, valueW
);
2901 update_reg_entries();
2903 update_system_links();
2904 init_system_links();
2906 ReleaseMutex(font_mutex
);
2911 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2914 TT_HoriHeader
*pHori
;
2918 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2919 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2921 if(height
== 0) height
= 16;
2923 /* Calc. height of EM square:
2925 * For +ve lfHeight we have
2926 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2927 * Re-arranging gives:
2928 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2930 * For -ve lfHeight we have
2932 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2933 * with il = winAscent + winDescent - units_per_em]
2938 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2939 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2940 pHori
->Ascender
- pHori
->Descender
);
2942 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2943 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2951 static struct font_mapping
*map_font_file( const char *name
)
2953 struct font_mapping
*mapping
;
2957 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2958 if (fstat( fd
, &st
) == -1) goto error
;
2960 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2962 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2964 mapping
->refcount
++;
2969 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2972 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2975 if (mapping
->data
== MAP_FAILED
)
2977 HeapFree( GetProcessHeap(), 0, mapping
);
2980 mapping
->refcount
= 1;
2981 mapping
->dev
= st
.st_dev
;
2982 mapping
->ino
= st
.st_ino
;
2983 mapping
->size
= st
.st_size
;
2984 list_add_tail( &mappings_list
, &mapping
->entry
);
2992 static void unmap_font_file( struct font_mapping
*mapping
)
2994 if (!--mapping
->refcount
)
2996 list_remove( &mapping
->entry
);
2997 munmap( mapping
->data
, mapping
->size
);
2998 HeapFree( GetProcessHeap(), 0, mapping
);
3002 static LONG
load_VDMX(GdiFont
*, LONG
);
3004 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3011 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3015 if (!(font
->mapping
= map_font_file( face
->file
)))
3017 WARN("failed to map %s\n", debugstr_a(face
->file
));
3020 data_ptr
= font
->mapping
->data
;
3021 data_size
= font
->mapping
->size
;
3025 data_ptr
= face
->font_data_ptr
;
3026 data_size
= face
->font_data_size
;
3029 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3031 ERR("FT_New_Face rets %d\n", err
);
3035 /* set it here, as load_VDMX needs it */
3036 font
->ft_face
= ft_face
;
3038 if(FT_IS_SCALABLE(ft_face
)) {
3039 /* load the VDMX table if we have one */
3040 font
->ppem
= load_VDMX(font
, height
);
3042 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3043 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3045 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3046 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3048 font
->ppem
= height
;
3049 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3050 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3056 static int get_nearest_charset(Face
*face
, int *cp
)
3058 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3059 a single face with the requested charset. The idea is to check if
3060 the selected font supports the current ANSI codepage, if it does
3061 return the corresponding charset, else return the first charset */
3064 int acp
= GetACP(), i
;
3068 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3069 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3070 return csi
.ciCharset
;
3072 for(i
= 0; i
< 32; i
++) {
3074 if(face
->fs
.fsCsb
[0] & fs0
) {
3075 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3077 return csi
.ciCharset
;
3080 FIXME("TCI failing on %x\n", fs0
);
3084 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3085 face
->fs
.fsCsb
[0], face
->file
);
3087 return DEFAULT_CHARSET
;
3090 static GdiFont
*alloc_font(void)
3092 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3094 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3095 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3097 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3098 ret
->total_kern_pairs
= (DWORD
)-1;
3099 ret
->kern_pairs
= NULL
;
3100 list_init(&ret
->hfontlist
);
3101 list_init(&ret
->child_fonts
);
3105 static void free_font(GdiFont
*font
)
3107 struct list
*cursor
, *cursor2
;
3110 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3112 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3113 struct list
*first_hfont
;
3114 HFONTLIST
*hfontlist
;
3115 list_remove(cursor
);
3118 first_hfont
= list_head(&child
->font
->hfontlist
);
3119 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3120 DeleteObject(hfontlist
->hfont
);
3121 HeapFree(GetProcessHeap(), 0, hfontlist
);
3122 free_font(child
->font
);
3124 HeapFree(GetProcessHeap(), 0, child
);
3127 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3128 if (font
->mapping
) unmap_font_file( font
->mapping
);
3129 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3130 HeapFree(GetProcessHeap(), 0, font
->potm
);
3131 HeapFree(GetProcessHeap(), 0, font
->name
);
3132 for (i
= 0; i
< font
->gmsize
; i
++)
3133 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3134 HeapFree(GetProcessHeap(), 0, font
->gm
);
3135 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3136 HeapFree(GetProcessHeap(), 0, font
);
3140 /*************************************************************
3143 * load the vdmx entry for the specified height
3146 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3147 ( ( (FT_ULong)_x4 << 24 ) | \
3148 ( (FT_ULong)_x3 << 16 ) | \
3149 ( (FT_ULong)_x2 << 8 ) | \
3152 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3167 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3171 BYTE devXRatio
, devYRatio
;
3172 USHORT numRecs
, numRatios
;
3173 DWORD result
, offset
= -1;
3177 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3179 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3182 /* FIXME: need the real device aspect ratio */
3186 numRecs
= GET_BE_WORD(hdr
[1]);
3187 numRatios
= GET_BE_WORD(hdr
[2]);
3189 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3190 for(i
= 0; i
< numRatios
; i
++) {
3193 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3194 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3197 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3199 if((ratio
.xRatio
== 0 &&
3200 ratio
.yStartRatio
== 0 &&
3201 ratio
.yEndRatio
== 0) ||
3202 (devXRatio
== ratio
.xRatio
&&
3203 devYRatio
>= ratio
.yStartRatio
&&
3204 devYRatio
<= ratio
.yEndRatio
))
3206 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3207 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3208 offset
= GET_BE_WORD(tmp
);
3214 FIXME("No suitable ratio found\n");
3218 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3220 BYTE startsz
, endsz
;
3223 recs
= GET_BE_WORD(group
.recs
);
3224 startsz
= group
.startsz
;
3225 endsz
= group
.endsz
;
3227 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3229 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3230 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3231 if(result
== GDI_ERROR
) {
3232 FIXME("Failed to retrieve vTable\n");
3237 for(i
= 0; i
< recs
; i
++) {
3238 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3239 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3240 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3242 if(yMax
+ -yMin
== height
) {
3245 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3248 if(yMax
+ -yMin
> height
) {
3251 goto end
; /* failed */
3253 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3254 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3255 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3256 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3262 TRACE("ppem not found for height %d\n", height
);
3266 HeapFree(GetProcessHeap(), 0, vTable
);
3272 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3274 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3275 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3276 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3277 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3278 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3281 static void calc_hash(FONT_DESC
*pfd
)
3283 DWORD hash
= 0, *ptr
, two_chars
;
3287 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3289 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3291 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3293 pwc
= (WCHAR
*)&two_chars
;
3295 *pwc
= toupperW(*pwc
);
3297 *pwc
= toupperW(*pwc
);
3301 hash
^= !pfd
->can_use_bitmap
;
3306 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3311 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3315 fd
.can_use_bitmap
= can_use_bitmap
;
3318 /* try the child list */
3319 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3320 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3321 if(!fontcmp(ret
, &fd
)) {
3322 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3323 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3324 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3325 if(hflist
->hfont
== hfont
)
3331 /* try the in-use list */
3332 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3333 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3334 if(!fontcmp(ret
, &fd
)) {
3335 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3336 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3337 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3338 if(hflist
->hfont
== hfont
)
3341 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3342 hflist
->hfont
= hfont
;
3343 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3348 /* then the unused list */
3349 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3350 while(font_elem_ptr
) {
3351 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3352 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3353 if(!fontcmp(ret
, &fd
)) {
3354 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3355 assert(list_empty(&ret
->hfontlist
));
3356 TRACE("Found %p in unused list\n", ret
);
3357 list_remove(&ret
->entry
);
3358 list_add_head(&gdi_font_list
, &ret
->entry
);
3359 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3360 hflist
->hfont
= hfont
;
3361 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3368 static void add_to_cache(GdiFont
*font
)
3370 static DWORD cache_num
= 1;
3372 font
->cache_num
= cache_num
++;
3373 list_add_head(&gdi_font_list
, &font
->entry
);
3376 /*************************************************************
3377 * create_child_font_list
3379 static BOOL
create_child_font_list(GdiFont
*font
)
3382 SYSTEM_LINKS
*font_link
;
3383 CHILD_FONT
*font_link_entry
, *new_child
;
3387 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3388 font_name
= psub
? psub
->to
.name
: font
->name
;
3389 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3391 if(!strcmpiW(font_link
->font_name
, font_name
))
3393 TRACE("found entry in system list\n");
3394 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3396 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3397 new_child
->face
= font_link_entry
->face
;
3398 new_child
->font
= NULL
;
3399 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3400 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3407 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3408 * Sans Serif. This is how asian windows get default fallbacks for fonts
3410 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3411 font
->charset
!= OEM_CHARSET
&&
3412 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3413 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3415 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3417 TRACE("found entry in default fallback list\n");
3418 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3420 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3421 new_child
->face
= font_link_entry
->face
;
3422 new_child
->font
= NULL
;
3423 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3424 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3434 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3436 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3438 if (pFT_Set_Charmap
)
3441 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3443 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3445 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3447 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3449 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3450 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3452 switch (ft_face
->charmaps
[i
]->platform_id
)
3455 cmap_def
= ft_face
->charmaps
[i
];
3457 case 0: /* Apple Unicode */
3458 cmap0
= ft_face
->charmaps
[i
];
3460 case 1: /* Macintosh */
3461 cmap1
= ft_face
->charmaps
[i
];
3464 cmap2
= ft_face
->charmaps
[i
];
3466 case 3: /* Microsoft */
3467 cmap3
= ft_face
->charmaps
[i
];
3472 if (cmap3
) /* prefer Microsoft cmap table */
3473 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3475 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3477 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3479 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3481 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3483 return ft_err
== FT_Err_Ok
;
3486 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3489 /*************************************************************
3490 * WineEngCreateFontInstance
3493 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3496 Face
*face
, *best
, *best_bitmap
;
3497 Family
*family
, *last_resort_family
;
3498 struct list
*family_elem_ptr
, *face_elem_ptr
;
3499 INT height
, width
= 0;
3500 unsigned int score
= 0, new_score
;
3501 signed int diff
= 0, newdiff
;
3502 BOOL bd
, it
, can_use_bitmap
;
3507 FontSubst
*psub
= NULL
;
3509 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3510 lf
.lfWidth
= abs(lf
.lfWidth
);
3512 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3514 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3515 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3516 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3519 if(dc
->GraphicsMode
== GM_ADVANCED
)
3520 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3523 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3524 font scaling abilities. */
3525 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3526 dcmat
.eM21
= dcmat
.eM12
= 0;
3529 /* Try to avoid not necessary glyph transformations */
3530 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3532 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3533 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3534 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3537 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3538 dcmat
.eM21
, dcmat
.eM22
);
3541 EnterCriticalSection( &freetype_cs
);
3543 /* check the cache first */
3544 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3545 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3546 LeaveCriticalSection( &freetype_cs
);
3550 TRACE("not in cache\n");
3551 if(list_empty(&font_list
)) /* No fonts installed */
3553 TRACE("No fonts installed\n");
3554 LeaveCriticalSection( &freetype_cs
);
3557 if(!have_installed_roman_font
)
3559 TRACE("No roman font installed\n");
3560 LeaveCriticalSection( &freetype_cs
);
3566 ret
->font_desc
.matrix
= dcmat
;
3567 ret
->font_desc
.lf
= lf
;
3568 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3569 calc_hash(&ret
->font_desc
);
3570 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3571 hflist
->hfont
= hfont
;
3572 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3574 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3575 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3576 original value lfCharSet. Note this is a special case for
3577 Symbol and doesn't happen at least for "Wingdings*" */
3579 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3580 lf
.lfCharSet
= SYMBOL_CHARSET
;
3582 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3583 switch(lf
.lfCharSet
) {
3584 case DEFAULT_CHARSET
:
3585 csi
.fs
.fsCsb
[0] = 0;
3588 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3589 csi
.fs
.fsCsb
[0] = 0;
3595 if(lf
.lfFaceName
[0] != '\0') {
3596 SYSTEM_LINKS
*font_link
;
3597 CHILD_FONT
*font_link_entry
;
3598 LPWSTR FaceName
= lf
.lfFaceName
;
3601 * Check for a leading '@' this signals that the font is being
3602 * requested in tategaki mode (vertical writing substitution) but
3603 * does not affect the fontface that is to be selected.
3605 if (lf
.lfFaceName
[0]=='@')
3606 FaceName
= &lf
.lfFaceName
[1];
3608 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3611 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3612 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3613 if (psub
->to
.charset
!= -1)
3614 lf
.lfCharSet
= psub
->to
.charset
;
3617 /* We want a match on name and charset or just name if
3618 charset was DEFAULT_CHARSET. If the latter then
3619 we fixup the returned charset later in get_nearest_charset
3620 where we'll either use the charset of the current ansi codepage
3621 or if that's unavailable the first charset that the font supports.
3623 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3624 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3625 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3626 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3628 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3629 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3630 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3631 if(face
->scalable
|| can_use_bitmap
)
3638 * Try check the SystemLink list first for a replacement font.
3639 * We may find good replacements there.
3641 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3643 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3644 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3646 TRACE("found entry in system list\n");
3647 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3649 face
= font_link_entry
->face
;
3650 family
= face
->family
;
3651 if(csi
.fs
.fsCsb
[0] &
3652 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3654 if(face
->scalable
|| can_use_bitmap
)
3662 psub
= NULL
; /* substitution is no more relevant */
3664 /* If requested charset was DEFAULT_CHARSET then try using charset
3665 corresponding to the current ansi codepage */
3666 if (!csi
.fs
.fsCsb
[0])
3669 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3670 FIXME("TCI failed on codepage %d\n", acp
);
3671 csi
.fs
.fsCsb
[0] = 0;
3673 lf
.lfCharSet
= csi
.ciCharset
;
3676 /* Face families are in the top 4 bits of lfPitchAndFamily,
3677 so mask with 0xF0 before testing */
3679 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3680 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3681 strcpyW(lf
.lfFaceName
, defFixed
);
3682 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3683 strcpyW(lf
.lfFaceName
, defSerif
);
3684 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3685 strcpyW(lf
.lfFaceName
, defSans
);
3687 strcpyW(lf
.lfFaceName
, defSans
);
3688 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3689 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3690 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3691 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3692 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3693 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3694 if(face
->scalable
|| can_use_bitmap
)
3700 last_resort_family
= NULL
;
3701 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3702 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3703 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3704 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3705 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3708 if(can_use_bitmap
&& !last_resort_family
)
3709 last_resort_family
= family
;
3714 if(last_resort_family
) {
3715 family
= last_resort_family
;
3716 csi
.fs
.fsCsb
[0] = 0;
3720 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3721 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3722 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3723 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3724 if(face
->scalable
) {
3725 csi
.fs
.fsCsb
[0] = 0;
3726 WARN("just using first face for now\n");
3729 if(can_use_bitmap
&& !last_resort_family
)
3730 last_resort_family
= family
;
3733 if(!last_resort_family
) {
3734 FIXME("can't find a single appropriate font - bailing\n");
3736 LeaveCriticalSection( &freetype_cs
);
3740 WARN("could only find a bitmap font - this will probably look awful!\n");
3741 family
= last_resort_family
;
3742 csi
.fs
.fsCsb
[0] = 0;
3745 it
= lf
.lfItalic
? 1 : 0;
3746 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3748 height
= lf
.lfHeight
;
3750 face
= best
= best_bitmap
= NULL
;
3751 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3753 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3757 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3758 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3759 new_score
= (italic
^ it
) + (bold
^ bd
);
3760 if(!best
|| new_score
<= score
)
3762 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3763 italic
, bold
, it
, bd
);
3766 if(best
->scalable
&& score
== 0) break;
3770 newdiff
= height
- (signed int)(best
->size
.height
);
3772 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3773 if(!best_bitmap
|| new_score
< score
||
3774 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3776 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3779 if(score
== 0 && diff
== 0) break;
3786 face
= best
->scalable
? best
: best_bitmap
;
3787 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3788 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3792 if(csi
.fs
.fsCsb
[0]) {
3793 ret
->charset
= lf
.lfCharSet
;
3794 ret
->codepage
= csi
.ciACP
;
3797 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3799 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3800 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3802 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3804 if(!face
->scalable
) {
3805 /* Windows uses integer scaling factors for bitmap fonts */
3806 INT scale
, scaled_height
;
3807 GdiFont
*cachedfont
;
3809 /* FIXME: rotation of bitmap fonts is ignored */
3810 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3812 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3813 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3814 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3815 /* As we changed the matrix, we need to search the cache for the font again,
3816 * otherwise we might explode the cache. */
3817 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3818 TRACE("Found cached font after non-scalable matrix rescale!\n");
3820 LeaveCriticalSection( &freetype_cs
);
3823 calc_hash(&ret
->font_desc
);
3825 if (height
!= 0) height
= diff
;
3826 height
+= face
->size
.height
;
3828 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3829 scaled_height
= scale
* face
->size
.height
;
3830 /* Only jump to the next height if the difference <= 25% original height */
3831 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3832 /* The jump between unscaled and doubled is delayed by 1 */
3833 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3834 ret
->scale_y
= scale
;
3836 width
= face
->size
.x_ppem
>> 6;
3837 height
= face
->size
.y_ppem
>> 6;
3841 TRACE("font scale y: %f\n", ret
->scale_y
);
3843 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3848 LeaveCriticalSection( &freetype_cs
);
3852 ret
->ntmFlags
= face
->ntmFlags
;
3854 if (ret
->charset
== SYMBOL_CHARSET
&&
3855 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3858 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3862 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3865 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3866 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3867 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3868 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3869 create_child_font_list(ret
);
3871 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3873 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3874 if (length
!= GDI_ERROR
)
3876 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3877 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3878 TRACE("Loaded GSUB table of %i bytes\n",length
);
3882 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3885 LeaveCriticalSection( &freetype_cs
);
3889 static void dump_gdi_font_list(void)
3892 struct list
*elem_ptr
;
3894 TRACE("---------- gdiFont Cache ----------\n");
3895 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3896 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3897 TRACE("gdiFont=%p %s %d\n",
3898 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3901 TRACE("---------- Unused gdiFont Cache ----------\n");
3902 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3903 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3904 TRACE("gdiFont=%p %s %d\n",
3905 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3909 /*************************************************************
3910 * WineEngDestroyFontInstance
3912 * free the gdiFont associated with this handle
3915 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3920 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3924 EnterCriticalSection( &freetype_cs
);
3926 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3928 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3929 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3930 if(hflist
->hfont
== handle
)
3932 TRACE("removing child font %p from child list\n", gdiFont
);
3933 list_remove(&gdiFont
->entry
);
3934 LeaveCriticalSection( &freetype_cs
);
3939 TRACE("destroying hfont=%p\n", handle
);
3941 dump_gdi_font_list();
3943 font_elem_ptr
= list_head(&gdi_font_list
);
3944 while(font_elem_ptr
) {
3945 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3946 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3948 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3949 while(hfontlist_elem_ptr
) {
3950 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3951 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3952 if(hflist
->hfont
== handle
) {
3953 list_remove(&hflist
->entry
);
3954 HeapFree(GetProcessHeap(), 0, hflist
);
3958 if(list_empty(&gdiFont
->hfontlist
)) {
3959 TRACE("Moving to Unused list\n");
3960 list_remove(&gdiFont
->entry
);
3961 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3966 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3967 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3968 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3969 while(font_elem_ptr
) {
3970 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3971 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3972 TRACE("freeing %p\n", gdiFont
);
3973 list_remove(&gdiFont
->entry
);
3976 LeaveCriticalSection( &freetype_cs
);
3980 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3981 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3986 if (face
->cached_enum_data
)
3989 *pelf
= face
->cached_enum_data
->elf
;
3990 *pntm
= face
->cached_enum_data
->ntm
;
3991 *ptype
= face
->cached_enum_data
->type
;
3995 font
= alloc_font();
3997 if(face
->scalable
) {
3998 height
= -2048; /* 2048 is the most common em size */
4001 height
= face
->size
.y_ppem
>> 6;
4002 width
= face
->size
.x_ppem
>> 6;
4004 font
->scale_y
= 1.0;
4006 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4012 font
->name
= strdupW(face
->family
->FamilyName
);
4013 font
->ntmFlags
= face
->ntmFlags
;
4015 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4017 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4019 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4021 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4022 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4024 lstrcpynW(pelf
->elfFullName
,
4025 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
4027 lstrcpynW(pelf
->elfStyle
,
4028 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4033 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4035 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4037 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4038 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4039 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4042 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4043 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4044 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4045 pntm
->ntmFontSig
= face
->fs
;
4047 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4049 pelf
->elfLogFont
.lfEscapement
= 0;
4050 pelf
->elfLogFont
.lfOrientation
= 0;
4051 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4052 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4053 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4054 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4055 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4056 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4057 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4058 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4059 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4060 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4061 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4064 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4065 *ptype
|= TRUETYPE_FONTTYPE
;
4066 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4067 *ptype
|= DEVICE_FONTTYPE
;
4068 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4069 *ptype
|= RASTER_FONTTYPE
;
4071 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4072 if (face
->cached_enum_data
)
4074 face
->cached_enum_data
->elf
= *pelf
;
4075 face
->cached_enum_data
->ntm
= *pntm
;
4076 face
->cached_enum_data
->type
= *ptype
;
4082 /*************************************************************
4086 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4090 struct list
*family_elem_ptr
, *face_elem_ptr
;
4092 NEWTEXTMETRICEXW ntm
;
4101 lf
.lfCharSet
= DEFAULT_CHARSET
;
4102 lf
.lfPitchAndFamily
= 0;
4103 lf
.lfFaceName
[0] = 0;
4107 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4110 EnterCriticalSection( &freetype_cs
);
4111 if(plf
->lfFaceName
[0]) {
4113 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4116 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4117 debugstr_w(psub
->to
.name
));
4119 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4123 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4124 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4125 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
4126 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4127 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4128 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4129 for(i
= 0; i
< 32; i
++) {
4130 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4131 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4132 strcpyW(elf
.elfScript
, OEM_DOSW
);
4133 i
= 32; /* break out of loop */
4134 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
4137 fs
.fsCsb
[0] = 1L << i
;
4139 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
4141 csi
.ciCharset
= DEFAULT_CHARSET
;
4142 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
4143 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
4144 elf
.elfLogFont
.lfCharSet
=
4145 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
4147 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
4149 FIXME("Unknown elfscript for bit %d\n", i
);
4152 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4153 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4154 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4155 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
4156 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4157 ntm
.ntmTm
.ntmFlags
);
4158 /* release section before callback (FIXME) */
4159 LeaveCriticalSection( &freetype_cs
);
4160 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
4161 EnterCriticalSection( &freetype_cs
);
4167 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4168 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4169 face_elem_ptr
= list_head(&family
->faces
);
4170 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4171 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4172 for(i
= 0; i
< 32; i
++) {
4173 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4174 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4175 strcpyW(elf
.elfScript
, OEM_DOSW
);
4176 i
= 32; /* break out of loop */
4177 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
4180 fs
.fsCsb
[0] = 1L << i
;
4182 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
4184 csi
.ciCharset
= DEFAULT_CHARSET
;
4185 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
4186 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
4187 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
4190 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
4192 FIXME("Unknown elfscript for bit %d\n", i
);
4195 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4196 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4197 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4198 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
4199 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4200 ntm
.ntmTm
.ntmFlags
);
4201 /* release section before callback (FIXME) */
4202 LeaveCriticalSection( &freetype_cs
);
4203 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
4204 EnterCriticalSection( &freetype_cs
);
4208 LeaveCriticalSection( &freetype_cs
);
4212 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4214 pt
->x
.value
= vec
->x
>> 6;
4215 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4216 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4217 pt
->y
.value
= vec
->y
>> 6;
4218 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4219 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4223 /***************************************************
4224 * According to the MSDN documentation on WideCharToMultiByte,
4225 * certain codepages cannot set the default_used parameter.
4226 * This returns TRUE if the codepage can set that parameter, false else
4227 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4229 static BOOL
codepage_sets_default_used(UINT codepage
)
4243 * GSUB Table handling functions
4246 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4248 const GSUB_CoverageFormat1
* cf1
;
4252 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4254 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4256 TRACE("Coverage Format 1, %i glyphs\n",count
);
4257 for (i
= 0; i
< count
; i
++)
4258 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4262 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4264 const GSUB_CoverageFormat2
* cf2
;
4267 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4269 count
= GET_BE_WORD(cf2
->RangeCount
);
4270 TRACE("Coverage Format 2, %i ranges\n",count
);
4271 for (i
= 0; i
< count
; i
++)
4273 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4275 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4276 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4278 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4279 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4285 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4290 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4292 const GSUB_ScriptList
*script
;
4293 const GSUB_Script
*deflt
= NULL
;
4295 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4297 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4298 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4300 const GSUB_Script
*scr
;
4303 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4304 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4306 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4308 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4314 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4318 const GSUB_LangSys
*Lang
;
4320 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4322 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4324 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4325 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4327 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4330 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4333 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4339 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4342 const GSUB_FeatureList
*feature
;
4343 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4345 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4346 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4348 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4349 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4351 const GSUB_Feature
*feat
;
4352 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4359 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4363 const GSUB_LookupList
*lookup
;
4364 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4366 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4367 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4369 const GSUB_LookupTable
*look
;
4370 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4371 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4372 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4373 if (GET_BE_WORD(look
->LookupType
) != 1)
4374 FIXME("We only handle SubType 1\n");
4379 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4381 const GSUB_SingleSubstFormat1
*ssf1
;
4382 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4383 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4384 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4386 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4387 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4388 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4390 TRACE(" Glyph 0x%x ->",glyph
);
4391 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4392 TRACE(" 0x%x\n",glyph
);
4397 const GSUB_SingleSubstFormat2
*ssf2
;
4401 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4402 offset
= GET_BE_WORD(ssf1
->Coverage
);
4403 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4404 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4405 TRACE(" Coverage index %i\n",index
);
4408 TRACE(" Glyph is 0x%x ->",glyph
);
4409 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4410 TRACE("0x%x\n",glyph
);
4419 static const char* get_opentype_script(const GdiFont
*font
)
4422 * I am not sure if this is the correct way to generate our script tag
4425 switch (font
->charset
)
4427 case ANSI_CHARSET
: return "latn";
4428 case BALTIC_CHARSET
: return "latn"; /* ?? */
4429 case CHINESEBIG5_CHARSET
: return "hani";
4430 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4431 case GB2312_CHARSET
: return "hani";
4432 case GREEK_CHARSET
: return "grek";
4433 case HANGUL_CHARSET
: return "hang";
4434 case RUSSIAN_CHARSET
: return "cyrl";
4435 case SHIFTJIS_CHARSET
: return "kana";
4436 case TURKISH_CHARSET
: return "latn"; /* ?? */
4437 case VIETNAMESE_CHARSET
: return "latn";
4438 case JOHAB_CHARSET
: return "latn"; /* ?? */
4439 case ARABIC_CHARSET
: return "arab";
4440 case HEBREW_CHARSET
: return "hebr";
4441 case THAI_CHARSET
: return "thai";
4442 default: return "latn";
4446 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4448 const GSUB_Header
*header
;
4449 const GSUB_Script
*script
;
4450 const GSUB_LangSys
*language
;
4451 const GSUB_Feature
*feature
;
4453 if (!font
->GSUB_Table
)
4456 header
= font
->GSUB_Table
;
4458 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4461 TRACE("Script not found\n");
4464 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4467 TRACE("Language not found\n");
4470 feature
= GSUB_get_feature(header
, language
, "vrt2");
4472 feature
= GSUB_get_feature(header
, language
, "vert");
4475 TRACE("vrt2/vert feature not found\n");
4478 return GSUB_apply_feature(header
, feature
, glyph
);
4481 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4485 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4486 WCHAR wc
= (WCHAR
)glyph
;
4488 BOOL
*default_used_pointer
;
4491 default_used_pointer
= NULL
;
4492 default_used
= FALSE
;
4493 if (codepage_sets_default_used(font
->codepage
))
4494 default_used_pointer
= &default_used
;
4495 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4498 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4499 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4500 return get_GSUB_vert_glyph(font
,ret
);
4503 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4504 glyph
= glyph
+ 0xf000;
4505 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4506 return get_GSUB_vert_glyph(font
,glyphId
);
4509 /*************************************************************
4510 * WineEngGetGlyphIndices
4513 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4514 LPWORD pgi
, DWORD flags
)
4517 int default_char
= -1;
4519 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4521 for(i
= 0; i
< count
; i
++)
4523 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4526 if (default_char
== -1)
4528 if (FT_IS_SFNT(font
->ft_face
))
4530 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4531 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4536 WineEngGetTextMetrics(font
, &textm
);
4537 default_char
= textm
.tmDefaultChar
;
4540 pgi
[i
] = default_char
;
4546 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4548 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4549 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4552 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4554 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4555 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4558 /*************************************************************
4559 * WineEngGetGlyphOutline
4561 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4562 * except that the first parameter is the HWINEENGFONT of the font in
4563 * question rather than an HDC.
4566 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4567 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4570 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4571 FT_Face ft_face
= incoming_font
->ft_face
;
4572 GdiFont
*font
= incoming_font
;
4573 FT_UInt glyph_index
;
4574 DWORD width
, height
, pitch
, needed
= 0;
4575 FT_Bitmap ft_bitmap
;
4577 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4579 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4580 double widthRatio
= 1.0;
4581 FT_Matrix transMat
= identityMat
;
4582 FT_Matrix transMatUnrotated
;
4583 BOOL needsTransform
= FALSE
;
4584 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4585 UINT original_index
;
4587 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4588 buflen
, buf
, lpmat
);
4590 TRACE("font transform %f %f %f %f\n",
4591 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4592 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4595 EnterCriticalSection( &freetype_cs
);
4597 if(format
& GGO_GLYPH_INDEX
) {
4598 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4599 original_index
= glyph
;
4600 format
&= ~GGO_GLYPH_INDEX
;
4602 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4603 ft_face
= font
->ft_face
;
4604 original_index
= glyph_index
;
4607 if(format
& GGO_UNHINTED
) {
4608 load_flags
|= FT_LOAD_NO_HINTING
;
4609 format
&= ~GGO_UNHINTED
;
4612 /* tategaki never appears to happen to lower glyph index */
4613 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4616 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4617 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4618 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4619 font
->gmsize
* sizeof(GM
*));
4621 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4622 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
4624 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4625 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4626 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4627 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4628 LeaveCriticalSection( &freetype_cs
);
4629 return 1; /* FIXME */
4633 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4634 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4636 /* Scaling factor */
4641 WineEngGetTextMetrics(font
, &tm
);
4643 widthRatio
= (double)font
->aveWidth
;
4644 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4647 widthRatio
= font
->scale_y
;
4649 /* Scaling transform */
4650 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4653 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4656 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4658 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4659 needsTransform
= TRUE
;
4662 /* Slant transform */
4663 if (font
->fake_italic
) {
4666 slantMat
.xx
= (1 << 16);
4667 slantMat
.xy
= ((1 << 16) >> 2);
4669 slantMat
.yy
= (1 << 16);
4670 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4671 needsTransform
= TRUE
;
4674 /* Rotation transform */
4675 transMatUnrotated
= transMat
;
4676 if(font
->orientation
&& !tategaki
) {
4677 FT_Matrix rotationMat
;
4679 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4680 pFT_Vector_Unit(&vecAngle
, angle
);
4681 rotationMat
.xx
= vecAngle
.x
;
4682 rotationMat
.xy
= -vecAngle
.y
;
4683 rotationMat
.yx
= -rotationMat
.xy
;
4684 rotationMat
.yy
= rotationMat
.xx
;
4686 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4687 needsTransform
= TRUE
;
4690 /* World transform */
4691 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4694 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4695 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4696 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4697 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4698 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4699 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4700 needsTransform
= TRUE
;
4703 /* Extra transformation specified by caller */
4704 if (!is_identity_MAT2(lpmat
))
4707 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4708 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
4709 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
4710 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4711 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4712 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4713 needsTransform
= TRUE
;
4716 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4717 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4718 format
== GGO_GRAY8_BITMAP
))
4720 load_flags
|= FT_LOAD_NO_BITMAP
;
4723 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4726 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4727 LeaveCriticalSection( &freetype_cs
);
4731 if(!needsTransform
) {
4732 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4733 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4734 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
4736 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4737 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4738 ft_face
->glyph
->metrics
.height
) & -64;
4739 lpgm
->gmCellIncX
= adv
;
4740 lpgm
->gmCellIncY
= 0;
4747 for(xc
= 0; xc
< 2; xc
++) {
4748 for(yc
= 0; yc
< 2; yc
++) {
4749 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4750 xc
* ft_face
->glyph
->metrics
.width
);
4751 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4752 yc
* ft_face
->glyph
->metrics
.height
;
4753 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4754 pFT_Vector_Transform(&vec
, &transMat
);
4755 if(xc
== 0 && yc
== 0) {
4756 left
= right
= vec
.x
;
4757 top
= bottom
= vec
.y
;
4759 if(vec
.x
< left
) left
= vec
.x
;
4760 else if(vec
.x
> right
) right
= vec
.x
;
4761 if(vec
.y
< bottom
) bottom
= vec
.y
;
4762 else if(vec
.y
> top
) top
= vec
.y
;
4767 right
= (right
+ 63) & -64;
4768 bottom
= bottom
& -64;
4769 top
= (top
+ 63) & -64;
4771 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4772 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4774 pFT_Vector_Transform(&vec
, &transMat
);
4775 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4776 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4778 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4780 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4781 adv
= (vec
.x
+63) >> 6;
4785 bbx
= (right
- left
) >> 6;
4786 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4787 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4788 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4789 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4791 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4792 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4793 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4795 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4796 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
4798 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4799 FONT_GM(font
,original_index
)->adv
= adv
;
4800 FONT_GM(font
,original_index
)->lsb
= lsb
;
4801 FONT_GM(font
,original_index
)->bbx
= bbx
;
4802 FONT_GM(font
,original_index
)->init
= TRUE
;
4805 if(format
== GGO_METRICS
)
4807 LeaveCriticalSection( &freetype_cs
);
4808 return 1; /* FIXME */
4811 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
4812 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4813 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4814 format
== GGO_GRAY8_BITMAP
))
4816 TRACE("loaded a bitmap\n");
4817 LeaveCriticalSection( &freetype_cs
);
4823 width
= lpgm
->gmBlackBoxX
;
4824 height
= lpgm
->gmBlackBoxY
;
4825 pitch
= ((width
+ 31) >> 5) << 2;
4826 needed
= pitch
* height
;
4828 if(!buf
|| !buflen
) break;
4830 switch(ft_face
->glyph
->format
) {
4831 case ft_glyph_format_bitmap
:
4833 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4834 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4835 INT h
= ft_face
->glyph
->bitmap
.rows
;
4837 memcpy(dst
, src
, w
);
4838 src
+= ft_face
->glyph
->bitmap
.pitch
;
4844 case ft_glyph_format_outline
:
4845 ft_bitmap
.width
= width
;
4846 ft_bitmap
.rows
= height
;
4847 ft_bitmap
.pitch
= pitch
;
4848 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4849 ft_bitmap
.buffer
= buf
;
4852 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4854 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4856 /* Note: FreeType will only set 'black' bits for us. */
4857 memset(buf
, 0, needed
);
4858 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4862 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4863 LeaveCriticalSection( &freetype_cs
);
4868 case GGO_GRAY2_BITMAP
:
4869 case GGO_GRAY4_BITMAP
:
4870 case GGO_GRAY8_BITMAP
:
4871 case WINE_GGO_GRAY16_BITMAP
:
4873 unsigned int mult
, row
, col
;
4876 width
= lpgm
->gmBlackBoxX
;
4877 height
= lpgm
->gmBlackBoxY
;
4878 pitch
= (width
+ 3) / 4 * 4;
4879 needed
= pitch
* height
;
4881 if(!buf
|| !buflen
) break;
4883 switch(ft_face
->glyph
->format
) {
4884 case ft_glyph_format_bitmap
:
4886 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4887 INT h
= ft_face
->glyph
->bitmap
.rows
;
4890 for(x
= 0; x
< pitch
; x
++)
4892 if(x
< ft_face
->glyph
->bitmap
.width
)
4893 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4897 src
+= ft_face
->glyph
->bitmap
.pitch
;
4900 LeaveCriticalSection( &freetype_cs
);
4903 case ft_glyph_format_outline
:
4905 ft_bitmap
.width
= width
;
4906 ft_bitmap
.rows
= height
;
4907 ft_bitmap
.pitch
= pitch
;
4908 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4909 ft_bitmap
.buffer
= buf
;
4912 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4914 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4916 memset(ft_bitmap
.buffer
, 0, buflen
);
4918 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4920 if(format
== GGO_GRAY2_BITMAP
)
4922 else if(format
== GGO_GRAY4_BITMAP
)
4924 else if(format
== GGO_GRAY8_BITMAP
)
4926 else /* format == WINE_GGO_GRAY16_BITMAP */
4928 LeaveCriticalSection( &freetype_cs
);
4934 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4935 LeaveCriticalSection( &freetype_cs
);
4940 for(row
= 0; row
< height
; row
++) {
4942 for(col
= 0; col
< width
; col
++, ptr
++) {
4943 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4950 case WINE_GGO_HRGB_BITMAP
:
4951 case WINE_GGO_HBGR_BITMAP
:
4952 case WINE_GGO_VRGB_BITMAP
:
4953 case WINE_GGO_VBGR_BITMAP
:
4954 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4956 switch (ft_face
->glyph
->format
)
4958 case FT_GLYPH_FORMAT_BITMAP
:
4963 width
= lpgm
->gmBlackBoxX
;
4964 height
= lpgm
->gmBlackBoxY
;
4966 needed
= pitch
* height
;
4968 if (!buf
|| !buflen
) break;
4970 memset(buf
, 0, buflen
);
4972 src
= ft_face
->glyph
->bitmap
.buffer
;
4973 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
4977 for (x
= 0; x
< width
; x
++)
4979 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
4980 ((unsigned int *)dst
)[x
] = ~0u;
4989 case FT_GLYPH_FORMAT_OUTLINE
:
4993 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
4994 INT x_shift
, y_shift
;
4996 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
4997 FT_Render_Mode render_mode
=
4998 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
4999 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5001 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5003 if ( render_mode
== FT_RENDER_MODE_LCD
)
5005 lpgm
->gmBlackBoxX
+= 2;
5006 lpgm
->gmptGlyphOrigin
.x
-= 1;
5010 lpgm
->gmBlackBoxY
+= 2;
5011 lpgm
->gmptGlyphOrigin
.y
+= 1;
5015 width
= lpgm
->gmBlackBoxX
;
5016 height
= lpgm
->gmBlackBoxY
;
5018 needed
= pitch
* height
;
5020 if (!buf
|| !buflen
) break;
5022 memset(buf
, 0, buflen
);
5024 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5026 if ( needsTransform
)
5027 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5029 if ( pFT_Library_SetLcdFilter
)
5030 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5031 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5033 src
= ft_face
->glyph
->bitmap
.buffer
;
5034 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5035 src_width
= ft_face
->glyph
->bitmap
.width
;
5036 src_height
= ft_face
->glyph
->bitmap
.rows
;
5038 if ( render_mode
== FT_RENDER_MODE_LCD
)
5046 rgb_interval
= src_pitch
;
5051 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5052 if ( x_shift
< 0 ) x_shift
= 0;
5053 if ( x_shift
+ (src_width
/ hmul
) > width
)
5054 x_shift
= width
- (src_width
/ hmul
);
5056 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5057 if ( y_shift
< 0 ) y_shift
= 0;
5058 if ( y_shift
+ (src_height
/ vmul
) > height
)
5059 y_shift
= height
- (src_height
/ vmul
);
5061 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5062 while ( src_height
)
5064 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5068 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5069 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5070 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5071 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5075 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5076 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5077 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5078 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5081 src
+= src_pitch
* vmul
;
5090 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5091 LeaveCriticalSection ( &freetype_cs
);
5098 LeaveCriticalSection( &freetype_cs
);
5104 int contour
, point
= 0, first_pt
;
5105 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5106 TTPOLYGONHEADER
*pph
;
5108 DWORD pph_start
, cpfx
, type
;
5110 if(buflen
== 0) buf
= NULL
;
5112 if (needsTransform
&& buf
) {
5113 pFT_Outline_Transform(outline
, &transMat
);
5116 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5118 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5121 pph
->dwType
= TT_POLYGON_TYPE
;
5122 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5124 needed
+= sizeof(*pph
);
5126 while(point
<= outline
->contours
[contour
]) {
5127 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5128 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5129 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5133 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5136 } while(point
<= outline
->contours
[contour
] &&
5137 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5138 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5139 /* At the end of a contour Windows adds the start point, but
5141 if(point
> outline
->contours
[contour
] &&
5142 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5144 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5146 } else if(point
<= outline
->contours
[contour
] &&
5147 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5148 /* add closing pt for bezier */
5150 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5158 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5161 pph
->cb
= needed
- pph_start
;
5167 /* Convert the quadratic Beziers to cubic Beziers.
5168 The parametric eqn for a cubic Bezier is, from PLRM:
5169 r(t) = at^3 + bt^2 + ct + r0
5170 with the control points:
5175 A quadratic Beizer has the form:
5176 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5178 So equating powers of t leads to:
5179 r1 = 2/3 p1 + 1/3 p0
5180 r2 = 2/3 p1 + 1/3 p2
5181 and of course r0 = p0, r3 = p2
5184 int contour
, point
= 0, first_pt
;
5185 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5186 TTPOLYGONHEADER
*pph
;
5188 DWORD pph_start
, cpfx
, type
;
5189 FT_Vector cubic_control
[4];
5190 if(buflen
== 0) buf
= NULL
;
5192 if (needsTransform
&& buf
) {
5193 pFT_Outline_Transform(outline
, &transMat
);
5196 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5198 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5201 pph
->dwType
= TT_POLYGON_TYPE
;
5202 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5204 needed
+= sizeof(*pph
);
5206 while(point
<= outline
->contours
[contour
]) {
5207 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5208 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5209 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5212 if(type
== TT_PRIM_LINE
) {
5214 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5218 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5221 /* FIXME: Possible optimization in endpoint calculation
5222 if there are two consecutive curves */
5223 cubic_control
[0] = outline
->points
[point
-1];
5224 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5225 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5226 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5227 cubic_control
[0].x
>>= 1;
5228 cubic_control
[0].y
>>= 1;
5230 if(point
+1 > outline
->contours
[contour
])
5231 cubic_control
[3] = outline
->points
[first_pt
];
5233 cubic_control
[3] = outline
->points
[point
+1];
5234 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5235 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5236 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5237 cubic_control
[3].x
>>= 1;
5238 cubic_control
[3].y
>>= 1;
5241 /* r1 = 1/3 p0 + 2/3 p1
5242 r2 = 1/3 p2 + 2/3 p1 */
5243 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5244 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5245 cubic_control
[2] = cubic_control
[1];
5246 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5247 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5248 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5249 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5251 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5252 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5253 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5258 } while(point
<= outline
->contours
[contour
] &&
5259 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5260 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5261 /* At the end of a contour Windows adds the start point,
5262 but only for Beziers and we've already done that.
5264 if(point
<= outline
->contours
[contour
] &&
5265 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5266 /* This is the closing pt of a bezier, but we've already
5267 added it, so just inc point and carry on */
5274 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5277 pph
->cb
= needed
- pph_start
;
5283 FIXME("Unsupported format %d\n", format
);
5284 LeaveCriticalSection( &freetype_cs
);
5287 LeaveCriticalSection( &freetype_cs
);
5291 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5293 FT_Face ft_face
= font
->ft_face
;
5294 #ifdef HAVE_FREETYPE_FTWINFNT_H
5295 FT_WinFNT_HeaderRec winfnt_header
;
5297 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5298 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5299 font
->potm
->otmSize
= size
;
5301 #define TM font->potm->otmTextMetrics
5302 #ifdef HAVE_FREETYPE_FTWINFNT_H
5303 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5305 TM
.tmHeight
= winfnt_header
.pixel_height
;
5306 TM
.tmAscent
= winfnt_header
.ascent
;
5307 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5308 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5309 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5310 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5311 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5312 TM
.tmWeight
= winfnt_header
.weight
;
5314 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5315 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5316 TM
.tmFirstChar
= winfnt_header
.first_char
;
5317 TM
.tmLastChar
= winfnt_header
.last_char
;
5318 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5319 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5320 TM
.tmItalic
= winfnt_header
.italic
;
5321 TM
.tmUnderlined
= font
->underline
;
5322 TM
.tmStruckOut
= font
->strikeout
;
5323 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5324 TM
.tmCharSet
= winfnt_header
.charset
;
5329 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5330 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5331 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5332 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5333 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5334 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5335 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5336 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5338 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5339 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5341 TM
.tmLastChar
= 255;
5342 TM
.tmDefaultChar
= 32;
5343 TM
.tmBreakChar
= 32;
5344 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5345 TM
.tmUnderlined
= font
->underline
;
5346 TM
.tmStruckOut
= font
->strikeout
;
5347 /* NB inverted meaning of TMPF_FIXED_PITCH */
5348 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5349 TM
.tmCharSet
= font
->charset
;
5357 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5359 double scale_x
, scale_y
;
5363 scale_x
= (double)font
->aveWidth
;
5364 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5367 scale_x
= font
->scale_y
;
5369 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5370 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5372 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5373 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5375 SCALE_Y(ptm
->tmHeight
);
5376 SCALE_Y(ptm
->tmAscent
);
5377 SCALE_Y(ptm
->tmDescent
);
5378 SCALE_Y(ptm
->tmInternalLeading
);
5379 SCALE_Y(ptm
->tmExternalLeading
);
5380 SCALE_Y(ptm
->tmOverhang
);
5382 SCALE_X(ptm
->tmAveCharWidth
);
5383 SCALE_X(ptm
->tmMaxCharWidth
);
5389 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5391 double scale_x
, scale_y
;
5395 scale_x
= (double)font
->aveWidth
;
5396 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5399 scale_x
= font
->scale_y
;
5401 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5402 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5404 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5406 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5407 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5409 SCALE_Y(potm
->otmAscent
);
5410 SCALE_Y(potm
->otmDescent
);
5411 SCALE_Y(potm
->otmLineGap
);
5412 SCALE_Y(potm
->otmsCapEmHeight
);
5413 SCALE_Y(potm
->otmsXHeight
);
5414 SCALE_Y(potm
->otmrcFontBox
.top
);
5415 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5416 SCALE_X(potm
->otmrcFontBox
.left
);
5417 SCALE_X(potm
->otmrcFontBox
.right
);
5418 SCALE_Y(potm
->otmMacAscent
);
5419 SCALE_Y(potm
->otmMacDescent
);
5420 SCALE_Y(potm
->otmMacLineGap
);
5421 SCALE_X(potm
->otmptSubscriptSize
.x
);
5422 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5423 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5424 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5425 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5426 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5427 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5428 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5429 SCALE_Y(potm
->otmsStrikeoutSize
);
5430 SCALE_Y(potm
->otmsStrikeoutPosition
);
5431 SCALE_Y(potm
->otmsUnderscoreSize
);
5432 SCALE_Y(potm
->otmsUnderscorePosition
);
5438 /*************************************************************
5439 * WineEngGetTextMetrics
5442 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5445 EnterCriticalSection( &freetype_cs
);
5447 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5448 if(!get_bitmap_text_metrics(font
))
5450 LeaveCriticalSection( &freetype_cs
);
5454 /* Make sure that the font has sane width/height ratio */
5457 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
5459 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
5465 *ptm
= font
->potm
->otmTextMetrics
;
5466 scale_font_metrics(font
, ptm
);
5467 LeaveCriticalSection( &freetype_cs
);
5471 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5475 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5477 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
5483 /*************************************************************
5484 * WineEngGetOutlineTextMetrics
5487 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5488 OUTLINETEXTMETRICW
*potm
)
5490 FT_Face ft_face
= font
->ft_face
;
5491 UINT needed
, lenfam
, lensty
, ret
;
5493 TT_HoriHeader
*pHori
;
5494 TT_Postscript
*pPost
;
5495 FT_Fixed x_scale
, y_scale
;
5496 WCHAR
*family_nameW
, *style_nameW
;
5497 static const WCHAR spaceW
[] = {' ', '\0'};
5499 INT ascent
, descent
;
5501 TRACE("font=%p\n", font
);
5503 if(!FT_IS_SCALABLE(ft_face
))
5507 EnterCriticalSection( &freetype_cs
);
5510 if(cbSize
>= font
->potm
->otmSize
)
5512 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5513 scale_outline_font_metrics(font
, potm
);
5515 LeaveCriticalSection( &freetype_cs
);
5516 return font
->potm
->otmSize
;
5520 needed
= sizeof(*potm
);
5522 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5523 family_nameW
= strdupW(font
->name
);
5525 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5527 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5528 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5529 style_nameW
, lensty
/sizeof(WCHAR
));
5531 /* These names should be read from the TT name table */
5533 /* length of otmpFamilyName */
5536 /* length of otmpFaceName */
5537 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5538 needed
+= lenfam
; /* just the family name */
5540 needed
+= lenfam
+ lensty
; /* family + " " + style */
5543 /* length of otmpStyleName */
5546 /* length of otmpFullName */
5547 needed
+= lenfam
+ lensty
;
5550 x_scale
= ft_face
->size
->metrics
.x_scale
;
5551 y_scale
= ft_face
->size
->metrics
.y_scale
;
5553 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5555 FIXME("Can't find OS/2 table - not TT font?\n");
5560 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5562 FIXME("Can't find HHEA table - not TT font?\n");
5567 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5569 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",
5570 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5571 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5572 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5573 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5574 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5576 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5577 font
->potm
->otmSize
= needed
;
5579 #define TM font->potm->otmTextMetrics
5581 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5582 ascent
= pHori
->Ascender
;
5583 descent
= -pHori
->Descender
;
5585 ascent
= pOS2
->usWinAscent
;
5586 descent
= pOS2
->usWinDescent
;
5590 TM
.tmAscent
= font
->yMax
;
5591 TM
.tmDescent
= -font
->yMin
;
5592 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5594 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5595 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5596 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5597 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5600 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5603 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5605 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5606 ((ascent
+ descent
) -
5607 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5609 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5610 if (TM
.tmAveCharWidth
== 0) {
5611 TM
.tmAveCharWidth
= 1;
5613 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5614 TM
.tmWeight
= FW_REGULAR
;
5615 if (font
->fake_bold
)
5616 TM
.tmWeight
= FW_BOLD
;
5619 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
5621 if (pOS2
->usWeightClass
> FW_MEDIUM
)
5622 TM
.tmWeight
= pOS2
->usWeightClass
;
5624 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
5625 TM
.tmWeight
= pOS2
->usWeightClass
;
5628 TM
.tmDigitizedAspectX
= 300;
5629 TM
.tmDigitizedAspectY
= 300;
5630 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5631 * symbol range to 0 - f0ff
5634 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
5639 case 1257: /* Baltic */
5640 TM
.tmLastChar
= 0xf8fd;
5643 TM
.tmLastChar
= 0xf0ff;
5645 TM
.tmBreakChar
= 0x20;
5646 TM
.tmDefaultChar
= 0x1f;
5650 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
5651 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
5653 if(pOS2
->usFirstCharIndex
<= 1)
5654 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
5655 else if (pOS2
->usFirstCharIndex
> 0xff)
5656 TM
.tmBreakChar
= 0x20;
5658 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
5659 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
5661 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5662 TM
.tmUnderlined
= font
->underline
;
5663 TM
.tmStruckOut
= font
->strikeout
;
5665 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5666 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5667 (pOS2
->version
== 0xFFFFU
||
5668 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5669 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5671 TM
.tmPitchAndFamily
= 0;
5673 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
5675 case PAN_FAMILY_SCRIPT
:
5676 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5679 case PAN_FAMILY_DECORATIVE
:
5680 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5685 case PAN_FAMILY_TEXT_DISPLAY
:
5686 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
5687 /* which is clearly not what the panose spec says. */
5689 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
5690 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
5691 TM
.tmPitchAndFamily
= FF_MODERN
;
5694 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
5699 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5702 case PAN_SERIF_COVE
:
5703 case PAN_SERIF_OBTUSE_COVE
:
5704 case PAN_SERIF_SQUARE_COVE
:
5705 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
5706 case PAN_SERIF_SQUARE
:
5707 case PAN_SERIF_THIN
:
5708 case PAN_SERIF_BONE
:
5709 case PAN_SERIF_EXAGGERATED
:
5710 case PAN_SERIF_TRIANGLE
:
5711 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5714 case PAN_SERIF_NORMAL_SANS
:
5715 case PAN_SERIF_OBTUSE_SANS
:
5716 case PAN_SERIF_PERP_SANS
:
5717 case PAN_SERIF_FLARED
:
5718 case PAN_SERIF_ROUNDED
:
5719 TM
.tmPitchAndFamily
|= FF_SWISS
;
5726 if(FT_IS_SCALABLE(ft_face
))
5727 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5729 if(FT_IS_SFNT(ft_face
))
5731 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5732 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5734 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5737 TM
.tmCharSet
= font
->charset
;
5739 font
->potm
->otmFiller
= 0;
5740 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5741 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5742 font
->potm
->otmfsType
= pOS2
->fsType
;
5743 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5744 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5745 font
->potm
->otmItalicAngle
= 0; /* POST table */
5746 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5747 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5748 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5749 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5750 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5751 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5752 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5753 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5754 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5755 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5756 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5757 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5758 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5759 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5760 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5761 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5762 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5763 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5764 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5765 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5766 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5767 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5768 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5769 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5771 font
->potm
->otmsUnderscoreSize
= 0;
5772 font
->potm
->otmsUnderscorePosition
= 0;
5774 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5775 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5779 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5780 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5781 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5782 strcpyW((WCHAR
*)cp
, family_nameW
);
5784 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5785 strcpyW((WCHAR
*)cp
, style_nameW
);
5787 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5788 strcpyW((WCHAR
*)cp
, family_nameW
);
5789 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5790 strcatW((WCHAR
*)cp
, spaceW
);
5791 strcatW((WCHAR
*)cp
, style_nameW
);
5792 cp
+= lenfam
+ lensty
;
5795 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5796 strcpyW((WCHAR
*)cp
, family_nameW
);
5797 strcatW((WCHAR
*)cp
, spaceW
);
5798 strcatW((WCHAR
*)cp
, style_nameW
);
5801 if(potm
&& needed
<= cbSize
)
5803 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5804 scale_outline_font_metrics(font
, potm
);
5808 HeapFree(GetProcessHeap(), 0, style_nameW
);
5809 HeapFree(GetProcessHeap(), 0, family_nameW
);
5811 LeaveCriticalSection( &freetype_cs
);
5815 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5817 HFONTLIST
*hfontlist
;
5818 child
->font
= alloc_font();
5819 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5820 if(!child
->font
->ft_face
)
5822 free_font(child
->font
);
5827 child
->font
->font_desc
= font
->font_desc
;
5828 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5829 child
->font
->orientation
= font
->orientation
;
5830 child
->font
->scale_y
= font
->scale_y
;
5831 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5832 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5833 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
5834 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5835 child
->font
->base_font
= font
;
5836 list_add_head(&child_font_list
, &child
->font
->entry
);
5837 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5841 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5844 CHILD_FONT
*child_font
;
5847 font
= font
->base_font
;
5849 *linked_font
= font
;
5851 if((*glyph
= get_glyph_index(font
, c
)))
5854 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5856 if(!child_font
->font
)
5857 if(!load_child_font(font
, child_font
))
5860 if(!child_font
->font
->ft_face
)
5862 g
= get_glyph_index(child_font
->font
, c
);
5866 *linked_font
= child_font
->font
;
5873 /*************************************************************
5874 * WineEngGetCharWidth
5877 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5880 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5883 FT_UInt glyph_index
;
5884 GdiFont
*linked_font
;
5886 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5889 EnterCriticalSection( &freetype_cs
);
5890 for(c
= firstChar
; c
<= lastChar
; c
++) {
5891 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5892 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5893 &gm
, 0, NULL
, &identity
);
5894 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5896 LeaveCriticalSection( &freetype_cs
);
5900 /*************************************************************
5901 * WineEngGetCharABCWidths
5904 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5907 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5910 FT_UInt glyph_index
;
5911 GdiFont
*linked_font
;
5913 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5915 if(!FT_IS_SCALABLE(font
->ft_face
))
5919 EnterCriticalSection( &freetype_cs
);
5921 for(c
= firstChar
; c
<= lastChar
; c
++) {
5922 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5923 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5924 &gm
, 0, NULL
, &identity
);
5925 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5926 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5927 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5928 FONT_GM(linked_font
,glyph_index
)->bbx
;
5930 LeaveCriticalSection( &freetype_cs
);
5934 /*************************************************************
5935 * WineEngGetCharABCWidthsFloat
5938 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
5940 static const MAT2 identity
= {{0,1}, {0,0}, {0,0}, {0,1}};
5943 FT_UInt glyph_index
;
5944 GdiFont
*linked_font
;
5946 TRACE("%p, %d, %d, %p\n", font
, first
, last
, buffer
);
5949 EnterCriticalSection( &freetype_cs
);
5951 for (c
= first
; c
<= last
; c
++)
5953 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5954 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5955 &gm
, 0, NULL
, &identity
);
5956 buffer
[c
- first
].abcfA
= FONT_GM(linked_font
, glyph_index
)->lsb
;
5957 buffer
[c
- first
].abcfB
= FONT_GM(linked_font
, glyph_index
)->bbx
;
5958 buffer
[c
- first
].abcfC
= FONT_GM(linked_font
, glyph_index
)->adv
-
5959 FONT_GM(linked_font
, glyph_index
)->lsb
-
5960 FONT_GM(linked_font
, glyph_index
)->bbx
;
5962 LeaveCriticalSection( &freetype_cs
);
5966 /*************************************************************
5967 * WineEngGetCharABCWidthsI
5970 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5973 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5976 FT_UInt glyph_index
;
5977 GdiFont
*linked_font
;
5979 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5983 EnterCriticalSection( &freetype_cs
);
5985 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5987 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5988 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5989 &gm
, 0, NULL
, &identity
);
5990 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5991 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5992 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5993 - FONT_GM(linked_font
,c
)->bbx
;
5996 for(c
= 0; c
< count
; c
++) {
5997 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5998 &gm
, 0, NULL
, &identity
);
5999 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6000 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6001 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6002 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6005 LeaveCriticalSection( &freetype_cs
);
6009 /*************************************************************
6010 * WineEngGetTextExtentExPoint
6013 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6014 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6016 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6021 FT_UInt glyph_index
;
6022 GdiFont
*linked_font
;
6024 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
6028 EnterCriticalSection( &freetype_cs
);
6031 WineEngGetTextMetrics(font
, &tm
);
6032 size
->cy
= tm
.tmHeight
;
6034 for(idx
= 0; idx
< count
; idx
++) {
6035 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
6036 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6037 &gm
, 0, NULL
, &identity
);
6038 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6040 if (! pnfit
|| ext
<= max_ext
) {
6050 LeaveCriticalSection( &freetype_cs
);
6051 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6055 /*************************************************************
6056 * WineEngGetTextExtentExPointI
6059 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6060 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6062 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6068 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
6071 EnterCriticalSection( &freetype_cs
);
6074 WineEngGetTextMetrics(font
, &tm
);
6075 size
->cy
= tm
.tmHeight
;
6077 for(idx
= 0; idx
< count
; idx
++) {
6078 WineEngGetGlyphOutline(font
, indices
[idx
],
6079 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
6081 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
6083 if (! pnfit
|| ext
<= max_ext
) {
6093 LeaveCriticalSection( &freetype_cs
);
6094 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6098 /*************************************************************
6099 * WineEngGetFontData
6102 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6105 FT_Face ft_face
= font
->ft_face
;
6109 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6110 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6111 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6113 if(!FT_IS_SFNT(ft_face
))
6121 if(table
) { /* MS tags differ in endianness from FT ones */
6122 table
= table
>> 24 | table
<< 24 |
6123 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
6126 /* make sure value of len is the value freetype says it needs */
6129 FT_ULong needed
= 0;
6130 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
6131 if( !err
&& needed
< len
) len
= needed
;
6133 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
6136 TRACE("Can't find table %c%c%c%c\n",
6137 /* bytes were reversed */
6138 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
6139 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
6145 /*************************************************************
6146 * WineEngGetTextFace
6149 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6151 INT n
= strlenW(font
->name
) + 1;
6153 lstrcpynW(str
, font
->name
, count
);
6154 return min(count
, n
);
6159 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6161 if (fs
) *fs
= font
->fs
;
6162 return font
->charset
;
6165 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6167 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6168 struct list
*first_hfont
;
6172 EnterCriticalSection( &freetype_cs
);
6173 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6174 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6175 if(font
== linked_font
)
6176 *new_hfont
= dc
->hFont
;
6179 first_hfont
= list_head(&linked_font
->hfontlist
);
6180 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6182 LeaveCriticalSection( &freetype_cs
);
6186 /* Retrieve a list of supported Unicode ranges for a given font.
6187 * Can be called with NULL gs to calculate the buffer size. Returns
6188 * the number of ranges found.
6190 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6192 DWORD num_ranges
= 0;
6194 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6197 FT_ULong char_code
, char_code_prev
;
6200 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6202 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6203 face
->num_glyphs
, glyph_code
, char_code
);
6205 if (!glyph_code
) return 0;
6209 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6210 gs
->ranges
[0].cGlyphs
= 0;
6211 gs
->cGlyphsSupported
= 0;
6217 if (char_code
< char_code_prev
)
6219 ERR("expected increasing char code from FT_Get_Next_Char\n");
6222 if (char_code
- char_code_prev
> 1)
6227 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6228 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6229 gs
->cGlyphsSupported
++;
6234 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6235 gs
->cGlyphsSupported
++;
6237 char_code_prev
= char_code
;
6238 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6242 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6247 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6250 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
6252 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6255 glyphset
->cbThis
= size
;
6256 glyphset
->cRanges
= num_ranges
;
6261 /*************************************************************
6264 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6268 EnterCriticalSection( &freetype_cs
);
6269 ret
= !list_empty(&font
->child_fonts
);
6270 LeaveCriticalSection( &freetype_cs
);
6274 static BOOL
is_hinting_enabled(void)
6276 /* Use the >= 2.2.0 function if available */
6277 if(pFT_Get_TrueType_Engine_Type
)
6279 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6280 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6282 #ifdef FT_DRIVER_HAS_HINTER
6287 /* otherwise if we've been compiled with < 2.2.0 headers
6288 use the internal macro */
6289 mod
= pFT_Get_Module(library
, "truetype");
6290 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6298 static BOOL
is_subpixel_rendering_enabled( void )
6300 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6301 return pFT_Library_SetLcdFilter
&&
6302 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6308 /*************************************************************************
6309 * GetRasterizerCaps (GDI32.@)
6311 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6313 static int hinting
= -1;
6314 static int subpixel
= -1;
6318 hinting
= is_hinting_enabled();
6319 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6322 if ( subpixel
== -1 )
6324 subpixel
= is_subpixel_rendering_enabled();
6325 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6328 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6329 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6331 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6332 lprs
->nLanguageID
= 0;
6336 /*************************************************************
6337 * WineEngRealizationInfo
6339 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6341 FIXME("(%p, %p): stub!\n", font
, info
);
6344 if(FT_IS_SCALABLE(font
->ft_face
))
6347 info
->cache_num
= font
->cache_num
;
6348 info
->unknown2
= -1;
6352 /*************************************************************************
6353 * Kerning support for TrueType fonts
6355 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6357 struct TT_kern_table
6363 struct TT_kern_subtable
6372 USHORT horizontal
: 1;
6374 USHORT cross_stream
: 1;
6375 USHORT override
: 1;
6376 USHORT reserved1
: 4;
6382 struct TT_format0_kern_subtable
6386 USHORT entrySelector
;
6397 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6398 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6399 const USHORT
*glyph_to_char
,
6400 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6403 const struct TT_kern_pair
*tt_kern_pair
;
6405 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6407 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6409 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6410 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6411 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6413 if (!kern_pair
|| !cPairs
)
6416 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6418 nPairs
= min(nPairs
, cPairs
);
6420 for (i
= 0; i
< nPairs
; i
++)
6422 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6423 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6424 /* this algorithm appears to better match what Windows does */
6425 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6426 if (kern_pair
->iKernAmount
< 0)
6428 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6429 kern_pair
->iKernAmount
-= font
->ppem
;
6431 else if (kern_pair
->iKernAmount
> 0)
6433 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6434 kern_pair
->iKernAmount
+= font
->ppem
;
6436 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6438 TRACE("left %u right %u value %d\n",
6439 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6443 TRACE("copied %u entries\n", nPairs
);
6447 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6451 const struct TT_kern_table
*tt_kern_table
;
6452 const struct TT_kern_subtable
*tt_kern_subtable
;
6454 USHORT
*glyph_to_char
;
6457 EnterCriticalSection( &freetype_cs
);
6458 if (font
->total_kern_pairs
!= (DWORD
)-1)
6460 if (cPairs
&& kern_pair
)
6462 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6463 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6464 LeaveCriticalSection( &freetype_cs
);
6467 LeaveCriticalSection( &freetype_cs
);
6468 return font
->total_kern_pairs
;
6471 font
->total_kern_pairs
= 0;
6473 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6475 if (length
== GDI_ERROR
)
6477 TRACE("no kerning data in the font\n");
6478 LeaveCriticalSection( &freetype_cs
);
6482 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6485 WARN("Out of memory\n");
6486 LeaveCriticalSection( &freetype_cs
);
6490 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6492 /* build a glyph index to char code map */
6493 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6496 WARN("Out of memory allocating a glyph index to char code map\n");
6497 HeapFree(GetProcessHeap(), 0, buf
);
6498 LeaveCriticalSection( &freetype_cs
);
6502 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6508 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6510 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6511 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6515 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6517 /* FIXME: This doesn't match what Windows does: it does some fancy
6518 * things with duplicate glyph index to char code mappings, while
6519 * we just avoid overriding existing entries.
6521 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6522 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6524 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6531 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6532 for (n
= 0; n
<= 65535; n
++)
6533 glyph_to_char
[n
] = (USHORT
)n
;
6536 tt_kern_table
= buf
;
6537 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6538 TRACE("version %u, nTables %u\n",
6539 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6541 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6543 for (i
= 0; i
< nTables
; i
++)
6545 struct TT_kern_subtable tt_kern_subtable_copy
;
6547 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6548 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6549 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6551 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6552 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6553 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6555 /* According to the TrueType specification this is the only format
6556 * that will be properly interpreted by Windows and OS/2
6558 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6560 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6562 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6563 glyph_to_char
, NULL
, 0);
6564 font
->total_kern_pairs
+= new_chunk
;
6566 if (!font
->kern_pairs
)
6567 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6568 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6570 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6571 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6573 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6574 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6577 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6579 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6582 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6583 HeapFree(GetProcessHeap(), 0, buf
);
6585 if (cPairs
&& kern_pair
)
6587 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6588 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6589 LeaveCriticalSection( &freetype_cs
);
6592 LeaveCriticalSection( &freetype_cs
);
6593 return font
->total_kern_pairs
;
6596 #else /* HAVE_FREETYPE */
6598 /*************************************************************************/
6600 BOOL
WineEngInit(void)
6604 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6608 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6613 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6618 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6619 LPWORD pgi
, DWORD flags
)
6624 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6625 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6628 ERR("called but we don't have FreeType\n");
6632 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6634 ERR("called but we don't have FreeType\n");
6638 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6639 OUTLINETEXTMETRICW
*potm
)
6641 ERR("called but we don't have FreeType\n");
6645 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6648 ERR("called but we don't have FreeType\n");
6652 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6655 ERR("called but we don't have FreeType\n");
6659 BOOL
WineEngGetCharABCWidthsFloat(GdiFont
*font
, UINT first
, UINT last
, LPABCFLOAT buffer
)
6661 ERR("called but we don't have FreeType\n");
6665 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6668 ERR("called but we don't have FreeType\n");
6672 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6673 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6675 ERR("called but we don't have FreeType\n");
6679 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6680 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6682 ERR("called but we don't have FreeType\n");
6686 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6689 ERR("called but we don't have FreeType\n");
6693 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6695 ERR("called but we don't have FreeType\n");
6699 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6701 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6705 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6707 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
6711 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6713 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
6717 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6719 FIXME("(%p, %p, %u): stub\n", font
, fs
, flags
);
6720 return DEFAULT_CHARSET
;
6723 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6728 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6730 FIXME("(%p, %p): stub\n", font
, glyphset
);
6734 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6739 /*************************************************************************
6740 * GetRasterizerCaps (GDI32.@)
6742 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6744 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6746 lprs
->nLanguageID
= 0;
6750 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6752 ERR("called but we don't have FreeType\n");
6756 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6758 ERR("called but we don't have FreeType\n");
6762 #endif /* HAVE_FREETYPE */