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/unicode.h"
88 #include "wine/debug.h"
89 #include "wine/list.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(font
);
95 #ifdef HAVE_FT2BUILD_H
98 #ifdef HAVE_FREETYPE_FREETYPE_H
99 #include <freetype/freetype.h>
101 #ifdef HAVE_FREETYPE_FTGLYPH_H
102 #include <freetype/ftglyph.h>
104 #ifdef HAVE_FREETYPE_TTTABLES_H
105 #include <freetype/tttables.h>
107 #ifdef HAVE_FREETYPE_FTTYPES_H
108 #include <freetype/fttypes.h>
110 #ifdef HAVE_FREETYPE_FTSNAMES_H
111 #include <freetype/ftsnames.h>
113 # ifdef HAVE_FREETYPE_FTNAMES_H
114 # include <freetype/ftnames.h>
117 #ifdef HAVE_FREETYPE_TTNAMEID_H
118 #include <freetype/ttnameid.h>
120 #ifdef HAVE_FREETYPE_FTOUTLN_H
121 #include <freetype/ftoutln.h>
123 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
124 #include <freetype/internal/sfnt.h>
126 #ifdef HAVE_FREETYPE_FTTRIGON_H
127 #include <freetype/fttrigon.h>
129 #ifdef HAVE_FREETYPE_FTWINFNT_H
130 #include <freetype/ftwinfnt.h>
132 #ifdef HAVE_FREETYPE_FTMODAPI_H
133 #include <freetype/ftmodapi.h>
135 #ifdef HAVE_FREETYPE_FTLCDFIL_H
136 #include <freetype/ftlcdfil.h>
139 #ifndef HAVE_FT_TRUETYPEENGINETYPE
142 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
143 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
144 FT_TRUETYPE_ENGINE_TYPE_PATENTED
145 } FT_TrueTypeEngineType
;
148 static FT_Library library
= 0;
155 static FT_Version_t FT_Version
;
156 static DWORD FT_SimpleVersion
;
158 static void *ft_handle
= NULL
;
160 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
161 MAKE_FUNCPTR(FT_Vector_Unit
);
162 MAKE_FUNCPTR(FT_Done_Face
);
163 MAKE_FUNCPTR(FT_Get_Char_Index
);
164 MAKE_FUNCPTR(FT_Get_Module
);
165 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
166 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
167 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
168 MAKE_FUNCPTR(FT_Init_FreeType
);
169 MAKE_FUNCPTR(FT_Load_Glyph
);
170 MAKE_FUNCPTR(FT_Matrix_Multiply
);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix
);
176 MAKE_FUNCPTR(FT_New_Face
);
177 MAKE_FUNCPTR(FT_New_Memory_Face
);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
179 MAKE_FUNCPTR(FT_Outline_Transform
);
180 MAKE_FUNCPTR(FT_Outline_Translate
);
181 MAKE_FUNCPTR(FT_Select_Charmap
);
182 MAKE_FUNCPTR(FT_Set_Charmap
);
183 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
184 MAKE_FUNCPTR(FT_Vector_Transform
);
185 MAKE_FUNCPTR(FT_Render_Glyph
);
186 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
187 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
188 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
189 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
190 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
191 #ifdef HAVE_FREETYPE_FTLCDFIL_H
192 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
194 #ifdef HAVE_FREETYPE_FTWINFNT_H
195 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
198 #ifdef SONAME_LIBFONTCONFIG
199 #include <fontconfig/fontconfig.h>
200 MAKE_FUNCPTR(FcConfigGetCurrent
);
201 MAKE_FUNCPTR(FcFontList
);
202 MAKE_FUNCPTR(FcFontSetDestroy
);
203 MAKE_FUNCPTR(FcInit
);
204 MAKE_FUNCPTR(FcObjectSetAdd
);
205 MAKE_FUNCPTR(FcObjectSetCreate
);
206 MAKE_FUNCPTR(FcObjectSetDestroy
);
207 MAKE_FUNCPTR(FcPatternCreate
);
208 MAKE_FUNCPTR(FcPatternDestroy
);
209 MAKE_FUNCPTR(FcPatternGetBool
);
210 MAKE_FUNCPTR(FcPatternGetString
);
216 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
217 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
218 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
221 #ifndef ft_encoding_none
222 #define FT_ENCODING_NONE ft_encoding_none
224 #ifndef ft_encoding_ms_symbol
225 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
227 #ifndef ft_encoding_unicode
228 #define FT_ENCODING_UNICODE ft_encoding_unicode
230 #ifndef ft_encoding_apple_roman
231 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
234 #ifdef WORDS_BIGENDIAN
235 #define GET_BE_WORD(x) (x)
237 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
240 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
247 FT_Short internal_leading
;
250 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
251 So to let this compile on older versions of FreeType we'll define the
252 new structure here. */
254 FT_Short height
, width
;
255 FT_Pos size
, x_ppem
, y_ppem
;
261 NEWTEXTMETRICEXW ntm
;
265 typedef struct tagFace
{
270 DWORD font_data_size
;
273 FONTSIGNATURE fs_links
;
275 FT_Fixed font_version
;
277 Bitmap_Size size
; /* set if face is a bitmap */
278 BOOL external
; /* TRUE if we should manually add this font to the registry */
279 struct tagFamily
*family
;
280 /* Cached data for Enum */
281 struct enum_data
*cached_enum_data
;
284 typedef struct tagFamily
{
286 const WCHAR
*FamilyName
;
292 INT adv
; /* These three hold to widths of the unrotated chars */
310 typedef struct tagHFONTLIST
{
325 struct list hfontlist
;
326 OUTLINETEXTMETRICW
*potm
;
327 DWORD total_kern_pairs
;
328 KERNINGPAIR
*kern_pairs
;
329 struct list child_fonts
;
331 /* the following members can be accessed without locking, they are never modified after creation */
333 struct font_mapping
*mapping
;
356 const WCHAR
*font_name
;
360 #define GM_BLOCK_SIZE 128
361 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
363 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
364 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
365 #define UNUSED_CACHE_SIZE 10
366 static struct list child_font_list
= LIST_INIT(child_font_list
);
367 static struct list system_links
= LIST_INIT(system_links
);
369 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
371 static struct list font_list
= LIST_INIT(font_list
);
373 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
374 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
375 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
377 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
378 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
379 'W','i','n','d','o','w','s','\\',
380 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
381 'F','o','n','t','s','\0'};
383 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
384 'W','i','n','d','o','w','s',' ','N','T','\\',
385 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
386 'F','o','n','t','s','\0'};
388 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
389 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
390 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
391 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
393 static const WCHAR
* const SystemFontValues
[4] = {
400 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
401 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
403 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
404 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
405 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
406 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
407 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
408 'E','u','r','o','p','e','a','n','\0'};
409 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
410 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
411 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
412 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
413 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
414 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
415 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
416 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
417 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
418 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
419 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
420 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
422 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
432 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
440 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
449 typedef struct tagFontSubst
{
465 static struct list mappings_list
= LIST_INIT( mappings_list
);
467 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
469 static CRITICAL_SECTION freetype_cs
;
470 static CRITICAL_SECTION_DEBUG critsect_debug
=
473 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
474 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
476 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
478 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
480 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
481 static BOOL use_default_fallback
= FALSE
;
483 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
485 /****************************************
486 * Notes on .fon files
488 * The fonts System, FixedSys and Terminal are special. There are typically multiple
489 * versions installed for different resolutions and codepages. Windows stores which one to use
490 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
492 * FIXEDFON.FON FixedSys
494 * OEMFONT.FON Terminal
495 * LogPixels Current dpi set by the display control panel applet
496 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
497 * also has a LogPixels value that appears to mirror this)
499 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
500 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
501 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
502 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
503 * so that makes sense.
505 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
506 * to be mapped into the registry on Windows 2000 at least).
509 * ega80woa.fon=ega80850.fon
510 * ega40woa.fon=ega40850.fon
511 * cga80woa.fon=cga80850.fon
512 * cga40woa.fon=cga40850.fon
515 /* These are all structures needed for the GSUB table */
517 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
518 #define TATEGAKI_LOWER_BOUND 0x02F1
534 GSUB_ScriptRecord ScriptRecord
[1];
540 } GSUB_LangSysRecord
;
545 GSUB_LangSysRecord LangSysRecord
[1];
549 WORD LookupOrder
; /* Reserved */
550 WORD ReqFeatureIndex
;
552 WORD FeatureIndex
[1];
558 } GSUB_FeatureRecord
;
562 GSUB_FeatureRecord FeatureRecord
[1];
566 WORD FeatureParams
; /* Reserved */
568 WORD LookupListIndex
[1];
587 } GSUB_CoverageFormat1
;
592 WORD StartCoverageIndex
;
598 GSUB_RangeRecord RangeRecord
[1];
599 } GSUB_CoverageFormat2
;
602 WORD SubstFormat
; /* = 1 */
605 } GSUB_SingleSubstFormat1
;
608 WORD SubstFormat
; /* = 2 */
612 }GSUB_SingleSubstFormat2
;
614 #ifdef HAVE_CARBON_CARBON_H
615 static char *find_cache_dir(void)
619 static char cached_path
[MAX_PATH
];
620 static const char *wine
= "/Wine", *fonts
= "/Fonts";
622 if(*cached_path
) return cached_path
;
624 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
627 WARN("can't create cached data folder\n");
630 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
633 WARN("can't create cached data path\n");
637 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
639 ERR("Could not create full path\n");
643 strcat(cached_path
, wine
);
645 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
647 WARN("Couldn't mkdir %s\n", cached_path
);
651 strcat(cached_path
, fonts
);
652 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
654 WARN("Couldn't mkdir %s\n", cached_path
);
661 /******************************************************************
664 * Extracts individual TrueType font files from a Mac suitcase font
665 * and saves them into the user's caches directory (see
667 * Returns a NULL terminated array of filenames.
669 * We do this because they are apps that try to read ttf files
670 * themselves and they don't like Mac suitcase files.
672 static char **expand_mac_font(const char *path
)
679 const char *filename
;
683 unsigned int size
, max_size
;
686 TRACE("path %s\n", path
);
688 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
691 WARN("failed to get ref\n");
695 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
698 TRACE("no data fork, so trying resource fork\n");
699 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
702 TRACE("unable to open resource fork\n");
709 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
712 CloseResFile(res_ref
);
716 out_dir
= find_cache_dir();
718 filename
= strrchr(path
, '/');
719 if(!filename
) filename
= path
;
722 /* output filename has the form out_dir/filename_%04x.ttf */
723 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
730 unsigned short *num_faces_ptr
, num_faces
, face
;
733 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
735 fond
= Get1IndResource(fond_res
, idx
);
737 TRACE("got fond resource %d\n", idx
);
740 fam_rec
= *(FamRec
**)fond
;
741 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
742 num_faces
= GET_BE_WORD(*num_faces_ptr
);
744 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
745 TRACE("num faces %04x\n", num_faces
);
746 for(face
= 0; face
< num_faces
; face
++, assoc
++)
749 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
750 unsigned short size
, font_id
;
753 size
= GET_BE_WORD(assoc
->fontSize
);
754 font_id
= GET_BE_WORD(assoc
->fontID
);
757 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
761 TRACE("trying to load sfnt id %04x\n", font_id
);
762 sfnt
= GetResource(sfnt_res
, font_id
);
765 TRACE("can't get sfnt resource %04x\n", font_id
);
769 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
774 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
776 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
777 if(fd
!= -1 || errno
== EEXIST
)
781 unsigned char *sfnt_data
;
784 sfnt_data
= *(unsigned char**)sfnt
;
785 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
789 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
792 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
794 ret
.array
[ret
.size
++] = output
;
798 WARN("unable to create %s\n", output
);
799 HeapFree(GetProcessHeap(), 0, output
);
802 ReleaseResource(sfnt
);
805 ReleaseResource(fond
);
808 CloseResFile(res_ref
);
813 #endif /* HAVE_CARBON_CARBON_H */
815 static inline BOOL
is_win9x(void)
817 return GetVersion() & 0x80000000;
820 This function builds an FT_Fixed from a double. It fails if the absolute
821 value of the float number is greater than 32768.
823 static inline FT_Fixed
FT_FixedFromFloat(double f
)
829 This function builds an FT_Fixed from a FIXED. It simply put f.value
830 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
832 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
834 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
838 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
843 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
844 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
846 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
847 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
849 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
851 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
853 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
857 file
= strrchr(face
->file
, '/');
862 if(!strcasecmp(file
, file_nameA
))
864 HeapFree(GetProcessHeap(), 0, file_nameA
);
869 HeapFree(GetProcessHeap(), 0, file_nameA
);
873 static Family
*find_family_from_name(const WCHAR
*name
)
877 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
879 if(!strcmpiW(family
->FamilyName
, name
))
886 static void DumpSubstList(void)
890 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
892 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
893 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
894 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
896 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
897 debugstr_w(psub
->to
.name
));
902 static LPWSTR
strdupW(LPCWSTR p
)
905 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
906 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
911 static LPSTR
strdupA(LPCSTR p
)
914 DWORD len
= (strlen(p
) + 1);
915 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
920 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
925 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
927 if(!strcmpiW(element
->from
.name
, from_name
) &&
928 (element
->from
.charset
== from_charset
||
929 element
->from
.charset
== -1))
936 #define ADD_FONT_SUBST_FORCE 1
938 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
940 FontSubst
*from_exist
, *to_exist
;
942 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
944 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
946 list_remove(&from_exist
->entry
);
947 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
948 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
949 HeapFree(GetProcessHeap(), 0, from_exist
);
955 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
959 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
960 subst
->to
.name
= strdupW(to_exist
->to
.name
);
963 list_add_tail(subst_list
, &subst
->entry
);
968 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
969 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
970 HeapFree(GetProcessHeap(), 0, subst
);
974 static void split_subst_info(NameCs
*nc
, LPSTR str
)
976 CHAR
*p
= strrchr(str
, ',');
981 nc
->charset
= strtol(p
+1, NULL
, 10);
984 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
985 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
986 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
989 static void LoadSubstList(void)
993 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
997 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
998 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
999 &hkey
) == ERROR_SUCCESS
) {
1001 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1002 &valuelen
, &datalen
, NULL
, NULL
);
1004 valuelen
++; /* returned value doesn't include room for '\0' */
1005 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1006 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1010 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1011 &dlen
) == ERROR_SUCCESS
) {
1012 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1014 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1015 split_subst_info(&psub
->from
, value
);
1016 split_subst_info(&psub
->to
, data
);
1018 /* Win 2000 doesn't allow mapping between different charsets
1019 or mapping of DEFAULT_CHARSET */
1020 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1021 psub
->to
.charset
== DEFAULT_CHARSET
) {
1022 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1023 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1024 HeapFree(GetProcessHeap(), 0, psub
);
1026 add_font_subst(&font_subst_list
, psub
, 0);
1028 /* reset dlen and vlen */
1032 HeapFree(GetProcessHeap(), 0, data
);
1033 HeapFree(GetProcessHeap(), 0, value
);
1039 /*****************************************************************
1040 * get_name_table_entry
1042 * Supply the platform, encoding, language and name ids in req
1043 * and if the name exists the function will fill in the string
1044 * and string_len members. The string is owned by FreeType so
1045 * don't free it. Returns TRUE if the name is found else FALSE.
1047 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1050 FT_UInt num_names
, name_index
;
1052 if(FT_IS_SFNT(ft_face
))
1054 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1056 for(name_index
= 0; name_index
< num_names
; name_index
++)
1058 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1060 if((name
.platform_id
== req
->platform_id
) &&
1061 (name
.encoding_id
== req
->encoding_id
) &&
1062 (name
.language_id
== req
->language_id
) &&
1063 (name
.name_id
== req
->name_id
))
1065 req
->string
= name
.string
;
1066 req
->string_len
= name
.string_len
;
1073 req
->string_len
= 0;
1077 static WCHAR
*get_familyname(FT_Face ft_face
)
1079 WCHAR
*family
= NULL
;
1082 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1083 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1084 name
.language_id
= GetUserDefaultLCID();
1085 name
.name_id
= TT_NAME_ID_FONT_FAMILY
;
1087 if(get_name_table_entry(ft_face
, &name
))
1091 /* String is not nul terminated and string_len is a byte length. */
1092 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1093 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1095 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1096 family
[i
] = GET_BE_WORD(*tmp
);
1099 TRACE("Got localised name %s\n", debugstr_w(family
));
1106 /*****************************************************************
1109 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1110 * of FreeType that don't export this function.
1113 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1118 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1119 if(pFT_Load_Sfnt_Table
)
1121 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1123 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1124 else /* Do it the hard way */
1126 TT_Face tt_face
= (TT_Face
) ft_face
;
1127 SFNT_Interface
*sfnt
;
1128 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1131 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1135 /* A field was added in the middle of the structure in 2.1.x */
1136 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1138 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1146 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1147 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1148 "Please upgrade your freetype library.\n");
1151 err
= FT_Err_Unimplemented_Feature
;
1157 static inline int TestStyles(DWORD flags
, DWORD styles
)
1159 return (flags
& styles
) == styles
;
1162 static int StyleOrdering(Face
*face
)
1164 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1166 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1168 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1170 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1173 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1174 debugstr_w(face
->family
->FamilyName
),
1175 debugstr_w(face
->StyleName
),
1181 /* Add a style of face to a font family using an ordering of the list such
1182 that regular fonts come before bold and italic, and single styles come
1183 before compound styles. */
1184 static void AddFaceToFamily(Face
*face
, Family
*family
)
1188 LIST_FOR_EACH( entry
, &family
->faces
)
1190 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1191 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1193 list_add_before( entry
, &face
->entry
);
1196 #define ADDFONT_EXTERNAL_FONT 0x01
1197 #define ADDFONT_FORCE_BITMAP 0x02
1198 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1202 TT_Header
*pHeader
= NULL
;
1203 WCHAR
*english_family
, *localised_family
, *StyleW
;
1207 struct list
*family_elem_ptr
, *face_elem_ptr
;
1209 FT_Long face_index
= 0, num_faces
;
1210 #ifdef HAVE_FREETYPE_FTWINFNT_H
1211 FT_WinFNT_HeaderRec winfnt_header
;
1213 int i
, bitmap_num
, internal_leading
;
1216 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1217 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1219 #ifdef HAVE_CARBON_CARBON_H
1220 if(file
&& !fake_family
)
1222 char **mac_list
= expand_mac_font(file
);
1225 BOOL had_one
= FALSE
;
1227 for(cursor
= mac_list
; *cursor
; cursor
++)
1230 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1231 HeapFree(GetProcessHeap(), 0, *cursor
);
1233 HeapFree(GetProcessHeap(), 0, mac_list
);
1238 #endif /* HAVE_CARBON_CARBON_H */
1241 char *family_name
= fake_family
;
1245 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1246 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1249 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1250 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1254 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1258 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*/
1259 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1260 pFT_Done_Face(ft_face
);
1264 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1265 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1266 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1267 pFT_Done_Face(ft_face
);
1271 if(FT_IS_SFNT(ft_face
))
1273 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1274 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1275 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1277 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1278 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1279 pFT_Done_Face(ft_face
);
1283 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1284 we don't want to load these. */
1285 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1289 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1291 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1292 pFT_Done_Face(ft_face
);
1298 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1299 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1300 pFT_Done_Face(ft_face
);
1304 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1306 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1307 pFT_Done_Face(ft_face
);
1313 localised_family
= get_familyname(ft_face
);
1314 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1316 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1317 HeapFree(GetProcessHeap(), 0, localised_family
);
1318 num_faces
= ft_face
->num_faces
;
1319 pFT_Done_Face(ft_face
);
1322 HeapFree(GetProcessHeap(), 0, localised_family
);
1326 family_name
= ft_face
->family_name
;
1330 My_FT_Bitmap_Size
*size
= NULL
;
1333 if(!FT_IS_SCALABLE(ft_face
))
1334 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1336 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1337 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1338 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1340 localised_family
= NULL
;
1342 localised_family
= get_familyname(ft_face
);
1343 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1344 HeapFree(GetProcessHeap(), 0, localised_family
);
1345 localised_family
= NULL
;
1350 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1351 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1352 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1357 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1358 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1359 list_init(&family
->faces
);
1360 list_add_tail(&font_list
, &family
->entry
);
1362 if(localised_family
) {
1363 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1364 subst
->from
.name
= strdupW(english_family
);
1365 subst
->from
.charset
= -1;
1366 subst
->to
.name
= strdupW(localised_family
);
1367 subst
->to
.charset
= -1;
1368 add_font_subst(&font_subst_list
, subst
, 0);
1371 HeapFree(GetProcessHeap(), 0, localised_family
);
1372 HeapFree(GetProcessHeap(), 0, english_family
);
1374 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1375 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1376 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1378 internal_leading
= 0;
1379 memset(&fs
, 0, sizeof(fs
));
1381 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1383 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1384 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1385 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1386 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1387 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1388 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1389 if(pOS2
->version
== 0) {
1392 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1393 fs
.fsCsb
[0] |= FS_LATIN1
;
1395 fs
.fsCsb
[0] |= FS_SYMBOL
;
1398 #ifdef HAVE_FREETYPE_FTWINFNT_H
1399 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1401 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1402 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1403 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1405 internal_leading
= winfnt_header
.internal_leading
;
1409 face_elem_ptr
= list_head(&family
->faces
);
1410 while(face_elem_ptr
) {
1411 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1412 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1413 if(!strcmpW(face
->StyleName
, StyleW
) &&
1414 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1415 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1416 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1417 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1420 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1421 HeapFree(GetProcessHeap(), 0, StyleW
);
1422 pFT_Done_Face(ft_face
);
1425 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1426 TRACE("Original font is newer so skipping this one\n");
1427 HeapFree(GetProcessHeap(), 0, StyleW
);
1428 pFT_Done_Face(ft_face
);
1431 TRACE("Replacing original with this one\n");
1432 list_remove(&face
->entry
);
1433 HeapFree(GetProcessHeap(), 0, face
->file
);
1434 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1435 HeapFree(GetProcessHeap(), 0, face
);
1440 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1441 face
->cached_enum_data
= NULL
;
1442 face
->StyleName
= StyleW
;
1445 face
->file
= strdupA(file
);
1446 face
->font_data_ptr
= NULL
;
1447 face
->font_data_size
= 0;
1452 face
->font_data_ptr
= font_data_ptr
;
1453 face
->font_data_size
= font_data_size
;
1455 face
->face_index
= face_index
;
1457 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1458 face
->ntmFlags
|= NTM_ITALIC
;
1459 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1460 face
->ntmFlags
|= NTM_BOLD
;
1461 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1462 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1463 face
->family
= family
;
1464 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1466 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1468 if(FT_IS_SCALABLE(ft_face
)) {
1469 memset(&face
->size
, 0, sizeof(face
->size
));
1470 face
->scalable
= TRUE
;
1472 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1473 size
->height
, size
->width
, size
->size
>> 6,
1474 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1475 face
->size
.height
= size
->height
;
1476 face
->size
.width
= size
->width
;
1477 face
->size
.size
= size
->size
;
1478 face
->size
.x_ppem
= size
->x_ppem
;
1479 face
->size
.y_ppem
= size
->y_ppem
;
1480 face
->size
.internal_leading
= internal_leading
;
1481 face
->scalable
= FALSE
;
1484 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1486 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1488 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1489 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1492 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1493 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1494 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1495 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1498 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1499 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1500 switch(ft_face
->charmaps
[i
]->encoding
) {
1501 case FT_ENCODING_UNICODE
:
1502 case FT_ENCODING_APPLE_ROMAN
:
1503 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1505 case FT_ENCODING_MS_SYMBOL
:
1506 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1514 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1515 have_installed_roman_font
= TRUE
;
1517 AddFaceToFamily(face
, family
);
1519 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1521 num_faces
= ft_face
->num_faces
;
1522 pFT_Done_Face(ft_face
);
1523 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1524 debugstr_w(StyleW
));
1525 } while(num_faces
> ++face_index
);
1529 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1531 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1534 static void DumpFontList(void)
1538 struct list
*family_elem_ptr
, *face_elem_ptr
;
1540 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1541 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1542 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1543 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1544 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1545 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1547 TRACE(" %d", face
->size
.height
);
1554 /***********************************************************
1555 * The replacement list is a way to map an entire font
1556 * family onto another family. For example adding
1558 * [HKCU\Software\Wine\Fonts\Replacements]
1559 * "Wingdings"="Winedings"
1561 * would enumerate the Winedings font both as Winedings and
1562 * Wingdings. However if a real Wingdings font is present the
1563 * replacement does not take place.
1566 static void LoadReplaceList(void)
1569 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1574 struct list
*family_elem_ptr
, *face_elem_ptr
;
1577 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1578 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1580 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1581 &valuelen
, &datalen
, NULL
, NULL
);
1583 valuelen
++; /* returned value doesn't include room for '\0' */
1584 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1585 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1589 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1590 &dlen
) == ERROR_SUCCESS
) {
1591 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1592 /* "NewName"="Oldname" */
1593 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1595 /* Find the old family and hence all of the font files
1597 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1598 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1599 if(!strcmpiW(family
->FamilyName
, data
)) {
1600 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1601 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1602 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1603 debugstr_w(face
->StyleName
), familyA
);
1604 /* Now add a new entry with the new family name */
1605 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1610 /* reset dlen and vlen */
1614 HeapFree(GetProcessHeap(), 0, data
);
1615 HeapFree(GetProcessHeap(), 0, value
);
1620 /*************************************************************
1623 static BOOL
init_system_links(void)
1625 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1626 'W','i','n','d','o','w','s',' ','N','T','\\',
1627 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1628 'S','y','s','t','e','m','L','i','n','k',0};
1631 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1632 WCHAR
*value
, *data
;
1633 WCHAR
*entry
, *next
;
1634 SYSTEM_LINKS
*font_link
, *system_font_link
;
1635 CHILD_FONT
*child_font
;
1636 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1637 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1638 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1644 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1646 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1647 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1648 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1649 val_len
= max_val
+ 1;
1650 data_len
= max_data
;
1652 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1654 TRACE("%s:\n", debugstr_w(value
));
1656 memset(&fs
, 0, sizeof(fs
));
1657 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1658 psub
= get_font_subst(&font_subst_list
, value
, -1);
1659 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1660 list_init(&font_link
->links
);
1661 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1664 CHILD_FONT
*child_font
;
1666 TRACE("\t%s\n", debugstr_w(entry
));
1668 next
= entry
+ strlenW(entry
) + 1;
1670 face_name
= strchrW(entry
, ',');
1674 while(isspaceW(*face_name
))
1677 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1679 face_name
= psub
->to
.name
;
1681 face
= find_face_from_filename(entry
, face_name
);
1684 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1688 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1689 child_font
->face
= face
;
1690 child_font
->font
= NULL
;
1691 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1692 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1693 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1694 list_add_tail(&font_link
->links
, &child_font
->entry
);
1696 family
= find_family_from_name(font_link
->font_name
);
1699 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1701 face
->fs_links
= fs
;
1704 list_add_tail(&system_links
, &font_link
->entry
);
1705 val_len
= max_val
+ 1;
1706 data_len
= max_data
;
1709 HeapFree(GetProcessHeap(), 0, value
);
1710 HeapFree(GetProcessHeap(), 0, data
);
1714 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1717 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1718 system_font_link
->font_name
= strdupW(System
);
1719 list_init(&system_font_link
->links
);
1721 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1724 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1725 child_font
->face
= face
;
1726 child_font
->font
= NULL
;
1727 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1728 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1730 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1732 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1734 CHILD_FONT
*font_link_entry
;
1735 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1737 CHILD_FONT
*new_child
;
1738 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1739 new_child
->face
= font_link_entry
->face
;
1740 new_child
->font
= NULL
;
1741 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1746 list_add_tail(&system_links
, &system_font_link
->entry
);
1750 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1753 struct dirent
*dent
;
1754 char path
[MAX_PATH
];
1756 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1758 dir
= opendir(dirname
);
1760 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1763 while((dent
= readdir(dir
)) != NULL
) {
1764 struct stat statbuf
;
1766 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1769 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1771 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1773 if(stat(path
, &statbuf
) == -1)
1775 WARN("Can't stat %s\n", debugstr_a(path
));
1778 if(S_ISDIR(statbuf
.st_mode
))
1779 ReadFontDir(path
, external_fonts
);
1781 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1787 static void load_fontconfig_fonts(void)
1789 #ifdef SONAME_LIBFONTCONFIG
1790 void *fc_handle
= NULL
;
1799 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1801 TRACE("Wine cannot find the fontconfig library (%s).\n",
1802 SONAME_LIBFONTCONFIG
);
1805 #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;}
1806 LOAD_FUNCPTR(FcConfigGetCurrent
);
1807 LOAD_FUNCPTR(FcFontList
);
1808 LOAD_FUNCPTR(FcFontSetDestroy
);
1809 LOAD_FUNCPTR(FcInit
);
1810 LOAD_FUNCPTR(FcObjectSetAdd
);
1811 LOAD_FUNCPTR(FcObjectSetCreate
);
1812 LOAD_FUNCPTR(FcObjectSetDestroy
);
1813 LOAD_FUNCPTR(FcPatternCreate
);
1814 LOAD_FUNCPTR(FcPatternDestroy
);
1815 LOAD_FUNCPTR(FcPatternGetBool
);
1816 LOAD_FUNCPTR(FcPatternGetString
);
1819 if(!pFcInit()) return;
1821 config
= pFcConfigGetCurrent();
1822 pat
= pFcPatternCreate();
1823 os
= pFcObjectSetCreate();
1824 pFcObjectSetAdd(os
, FC_FILE
);
1825 pFcObjectSetAdd(os
, FC_SCALABLE
);
1826 fontset
= pFcFontList(config
, pat
, os
);
1827 if(!fontset
) return;
1828 for(i
= 0; i
< fontset
->nfont
; i
++) {
1831 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1833 TRACE("fontconfig: %s\n", file
);
1835 /* We're just interested in OT/TT fonts for now, so this hack just
1836 picks up the scalable fonts without extensions .pf[ab] to save time
1837 loading every other font */
1839 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1841 TRACE("not scalable\n");
1845 len
= strlen( file
);
1846 if(len
< 4) continue;
1847 ext
= &file
[ len
- 3 ];
1848 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1849 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1851 pFcFontSetDestroy(fontset
);
1852 pFcObjectSetDestroy(os
);
1853 pFcPatternDestroy(pat
);
1859 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1862 const char *data_dir
= wine_get_data_dir();
1864 if (!data_dir
) data_dir
= wine_get_build_dir();
1871 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1873 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1875 strcpy(unix_name
, data_dir
);
1876 strcat(unix_name
, "/fonts/");
1878 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1880 EnterCriticalSection( &freetype_cs
);
1881 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1882 LeaveCriticalSection( &freetype_cs
);
1883 HeapFree(GetProcessHeap(), 0, unix_name
);
1888 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1890 static const WCHAR slashW
[] = {'\\','\0'};
1892 WCHAR windowsdir
[MAX_PATH
];
1895 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1896 strcatW(windowsdir
, fontsW
);
1897 strcatW(windowsdir
, slashW
);
1898 strcatW(windowsdir
, file
);
1899 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1900 EnterCriticalSection( &freetype_cs
);
1901 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1902 LeaveCriticalSection( &freetype_cs
);
1903 HeapFree(GetProcessHeap(), 0, unixname
);
1908 static void load_system_fonts(void)
1911 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1912 const WCHAR
* const *value
;
1914 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1917 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1918 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1919 strcatW(windowsdir
, fontsW
);
1920 for(value
= SystemFontValues
; *value
; value
++) {
1921 dlen
= sizeof(data
);
1922 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1926 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1927 if((unixname
= wine_get_unix_file_name(pathW
))) {
1928 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1929 HeapFree(GetProcessHeap(), 0, unixname
);
1932 load_font_from_data_dir(data
);
1939 /*************************************************************
1941 * This adds registry entries for any externally loaded fonts
1942 * (fonts from fontconfig or FontDirs). It also deletes entries
1943 * of no longer existing fonts.
1946 static void update_reg_entries(void)
1948 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1953 struct list
*family_elem_ptr
, *face_elem_ptr
;
1955 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1956 static const WCHAR spaceW
[] = {' ', '\0'};
1959 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1960 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1961 ERR("Can't create Windows font reg key\n");
1965 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1966 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1967 ERR("Can't create Windows font reg key\n");
1971 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1972 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1973 ERR("Can't create external font reg key\n");
1977 /* enumerate the fonts and add external ones to the two keys */
1979 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1980 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1981 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1982 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1983 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1984 if(!face
->external
) continue;
1986 if (!(face
->ntmFlags
& NTM_REGULAR
))
1987 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1988 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1989 strcpyW(valueW
, family
->FamilyName
);
1990 if(len
!= len_fam
) {
1991 strcatW(valueW
, spaceW
);
1992 strcatW(valueW
, face
->StyleName
);
1994 strcatW(valueW
, TrueType
);
1996 file
= wine_get_dos_file_name(face
->file
);
1998 len
= strlenW(file
) + 1;
2001 if((path
= strrchr(face
->file
, '/')) == NULL
)
2005 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2007 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2008 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2010 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2011 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2012 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2014 HeapFree(GetProcessHeap(), 0, file
);
2015 HeapFree(GetProcessHeap(), 0, valueW
);
2019 if(external_key
) RegCloseKey(external_key
);
2020 if(win9x_key
) RegCloseKey(win9x_key
);
2021 if(winnt_key
) RegCloseKey(winnt_key
);
2025 static void delete_external_font_keys(void)
2027 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2028 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2032 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2033 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2034 ERR("Can't create Windows font reg key\n");
2038 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2039 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2040 ERR("Can't create Windows font reg key\n");
2044 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2045 ERR("Can't create external font reg key\n");
2049 /* Delete all external fonts added last time */
2051 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2052 &valuelen
, &datalen
, NULL
, NULL
);
2053 valuelen
++; /* returned value doesn't include room for '\0' */
2054 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2055 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2057 dlen
= datalen
* sizeof(WCHAR
);
2060 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2061 &dlen
) == ERROR_SUCCESS
) {
2063 RegDeleteValueW(winnt_key
, valueW
);
2064 RegDeleteValueW(win9x_key
, valueW
);
2065 /* reset dlen and vlen */
2069 HeapFree(GetProcessHeap(), 0, data
);
2070 HeapFree(GetProcessHeap(), 0, valueW
);
2072 /* Delete the old external fonts key */
2073 RegCloseKey(external_key
);
2074 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2077 if(win9x_key
) RegCloseKey(win9x_key
);
2078 if(winnt_key
) RegCloseKey(winnt_key
);
2081 /*************************************************************
2082 * WineEngAddFontResourceEx
2085 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2091 if (ft_handle
) /* do it only if we have freetype up and running */
2096 FIXME("Ignoring flags %x\n", flags
);
2098 if((unixname
= wine_get_unix_file_name(file
)))
2100 EnterCriticalSection( &freetype_cs
);
2101 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2102 LeaveCriticalSection( &freetype_cs
);
2103 HeapFree(GetProcessHeap(), 0, unixname
);
2105 if (!ret
&& !strchrW(file
, '\\')) {
2106 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2107 ret
= load_font_from_winfonts_dir(file
);
2109 /* Try in datadir/fonts (or builddir/fonts),
2110 * needed for Magic the Gathering Online
2112 ret
= load_font_from_data_dir(file
);
2119 /*************************************************************
2120 * WineEngAddFontMemResourceEx
2123 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2127 if (ft_handle
) /* do it only if we have freetype up and running */
2129 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2131 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2132 memcpy(pFontCopy
, pbFont
, cbFont
);
2134 EnterCriticalSection( &freetype_cs
);
2135 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2136 LeaveCriticalSection( &freetype_cs
);
2140 TRACE("AddFontToList failed\n");
2141 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2144 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2145 * For now return something unique but quite random
2147 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2148 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2155 /*************************************************************
2156 * WineEngRemoveFontResourceEx
2159 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2166 static const struct nls_update_font_list
2168 UINT ansi_cp
, oem_cp
;
2169 const char *oem
, *fixed
, *system
;
2170 const char *courier
, *serif
, *small
, *sserif
;
2171 /* these are for font substitutes */
2172 const char *shelldlg
, *tmsrmn
;
2173 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2177 const char *from
, *to
;
2178 } arial_0
, courier_new_0
, times_new_roman_0
;
2179 } nls_update_font_list
[] =
2181 /* Latin 1 (United States) */
2182 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2183 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2184 "Tahoma","Times New Roman",
2185 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2188 /* Latin 1 (Multilingual) */
2189 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2190 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2191 "Tahoma","Times New Roman", /* FIXME unverified */
2192 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2195 /* Eastern Europe */
2196 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2197 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2198 "Tahoma","Times New Roman", /* FIXME unverified */
2199 "Fixedsys,238", "System,238",
2200 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2201 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2202 { "Arial CE,0", "Arial,238" },
2203 { "Courier New CE,0", "Courier New,238" },
2204 { "Times New Roman CE,0", "Times New Roman,238" }
2207 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2208 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2209 "Tahoma","Times New Roman", /* FIXME unverified */
2210 "Fixedsys,204", "System,204",
2211 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2212 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2213 { "Arial Cyr,0", "Arial,204" },
2214 { "Courier New Cyr,0", "Courier New,204" },
2215 { "Times New Roman Cyr,0", "Times New Roman,204" }
2218 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2219 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2220 "Tahoma","Times New Roman", /* FIXME unverified */
2221 "Fixedsys,161", "System,161",
2222 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2223 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2224 { "Arial Greek,0", "Arial,161" },
2225 { "Courier New Greek,0", "Courier New,161" },
2226 { "Times New Roman Greek,0", "Times New Roman,161" }
2229 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2230 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2231 "Tahoma","Times New Roman", /* FIXME unverified */
2232 "Fixedsys,162", "System,162",
2233 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2234 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2235 { "Arial Tur,0", "Arial,162" },
2236 { "Courier New Tur,0", "Courier New,162" },
2237 { "Times New Roman Tur,0", "Times New Roman,162" }
2240 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2241 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2242 "Tahoma","Times New Roman", /* FIXME unverified */
2243 "Fixedsys,177", "System,177",
2244 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2245 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2249 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2250 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2251 "Tahoma","Times New Roman", /* FIXME unverified */
2252 "Fixedsys,178", "System,178",
2253 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2254 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2258 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2259 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2260 "Tahoma","Times New Roman", /* FIXME unverified */
2261 "Fixedsys,186", "System,186",
2262 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2263 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2264 { "Arial Baltic,0", "Arial,186" },
2265 { "Courier New Baltic,0", "Courier New,186" },
2266 { "Times New Roman Baltic,0", "Times New Roman,186" }
2269 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2270 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2271 "Tahoma","Times New Roman", /* FIXME unverified */
2272 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2276 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2277 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2278 "Tahoma","Times New Roman", /* FIXME unverified */
2279 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2283 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2284 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2285 "MS UI Gothic","MS Serif",
2286 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2289 /* Chinese Simplified */
2290 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2291 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2292 "SimSun", "NSimSun",
2293 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2297 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2298 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2300 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2303 /* Chinese Traditional */
2304 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2306 "PMingLiU", "MingLiU",
2307 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2312 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2314 return ( ansi_cp
== 932 /* CP932 for Japanese */
2315 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2316 || ansi_cp
== 949 /* CP949 for Korean */
2317 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2320 static inline HKEY
create_fonts_NT_registry_key(void)
2324 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2325 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2329 static inline HKEY
create_fonts_9x_registry_key(void)
2333 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2334 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2338 static inline HKEY
create_config_fonts_registry_key(void)
2342 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2343 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2347 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2349 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2350 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2351 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2352 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2355 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2358 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2360 RegDeleteValueA(hkey
, name
);
2363 static void update_font_info(void)
2365 char buf
[40], cpbuf
[40];
2368 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2371 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2374 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2375 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2376 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2377 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2378 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2380 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2381 if (is_dbcs_ansi_cp(ansi_cp
))
2382 use_default_fallback
= TRUE
;
2385 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2387 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2392 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2394 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2396 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2399 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2403 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2404 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2406 hkey
= create_config_fonts_registry_key();
2407 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2408 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2409 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2412 hkey
= create_fonts_NT_registry_key();
2413 add_font_list(hkey
, &nls_update_font_list
[i
]);
2416 hkey
= create_fonts_9x_registry_key();
2417 add_font_list(hkey
, &nls_update_font_list
[i
]);
2420 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2422 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2423 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2424 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2425 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2427 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2428 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2429 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2430 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2431 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2432 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2433 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2434 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2436 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2437 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2438 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2446 /* Delete the FontSubstitutes from other locales */
2447 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2449 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2450 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2451 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2457 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2461 static BOOL
init_freetype(void)
2463 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2466 "Wine cannot find the FreeType font library. To enable Wine to\n"
2467 "use TrueType fonts please install a version of FreeType greater than\n"
2468 "or equal to 2.0.5.\n"
2469 "http://www.freetype.org\n");
2473 #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;}
2475 LOAD_FUNCPTR(FT_Vector_Unit
)
2476 LOAD_FUNCPTR(FT_Done_Face
)
2477 LOAD_FUNCPTR(FT_Get_Char_Index
)
2478 LOAD_FUNCPTR(FT_Get_Module
)
2479 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2480 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2481 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2482 LOAD_FUNCPTR(FT_Init_FreeType
)
2483 LOAD_FUNCPTR(FT_Load_Glyph
)
2484 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2485 #ifndef FT_MULFIX_INLINED
2486 LOAD_FUNCPTR(FT_MulFix
)
2488 LOAD_FUNCPTR(FT_New_Face
)
2489 LOAD_FUNCPTR(FT_New_Memory_Face
)
2490 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2491 LOAD_FUNCPTR(FT_Outline_Transform
)
2492 LOAD_FUNCPTR(FT_Outline_Translate
)
2493 LOAD_FUNCPTR(FT_Select_Charmap
)
2494 LOAD_FUNCPTR(FT_Set_Charmap
)
2495 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2496 LOAD_FUNCPTR(FT_Vector_Transform
)
2497 LOAD_FUNCPTR(FT_Render_Glyph
)
2500 /* Don't warn if these ones are missing */
2501 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2502 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2503 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2504 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2505 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2506 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2507 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2509 #ifdef HAVE_FREETYPE_FTWINFNT_H
2510 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2512 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2513 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2514 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2515 <= 2.0.3 has FT_Sqrt64 */
2519 if(pFT_Init_FreeType(&library
) != 0) {
2520 ERR("Can't init FreeType library\n");
2521 wine_dlclose(ft_handle
, NULL
, 0);
2525 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2526 if (pFT_Library_Version
)
2527 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2529 if (FT_Version
.major
<=0)
2535 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2536 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2537 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2538 ((FT_Version
.patch
) & 0x0000ff);
2544 "Wine cannot find certain functions that it needs inside the FreeType\n"
2545 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2546 "FreeType to at least version 2.0.5.\n"
2547 "http://www.freetype.org\n");
2548 wine_dlclose(ft_handle
, NULL
, 0);
2553 /*************************************************************
2556 * Initialize FreeType library and create a list of available faces
2558 BOOL
WineEngInit(void)
2560 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2561 static const WCHAR pathW
[] = {'P','a','t','h',0};
2563 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2564 WCHAR windowsdir
[MAX_PATH
];
2567 const char *data_dir
;
2571 /* update locale dependent font info in registry */
2574 if(!init_freetype()) return FALSE
;
2576 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2577 ERR("Failed to create font mutex\n");
2580 WaitForSingleObject(font_mutex
, INFINITE
);
2582 delete_external_font_keys();
2584 /* load the system bitmap fonts */
2585 load_system_fonts();
2587 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2588 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2589 strcatW(windowsdir
, fontsW
);
2590 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2592 ReadFontDir(unixname
, FALSE
);
2593 HeapFree(GetProcessHeap(), 0, unixname
);
2596 /* load the system truetype fonts */
2597 data_dir
= wine_get_data_dir();
2598 if (!data_dir
) data_dir
= wine_get_build_dir();
2599 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2600 strcpy(unixname
, data_dir
);
2601 strcat(unixname
, "/fonts/");
2602 ReadFontDir(unixname
, TRUE
);
2603 HeapFree(GetProcessHeap(), 0, unixname
);
2606 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2607 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2608 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2610 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2611 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2612 &hkey
) == ERROR_SUCCESS
) {
2613 LPWSTR data
, valueW
;
2614 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2615 &valuelen
, &datalen
, NULL
, NULL
);
2617 valuelen
++; /* returned value doesn't include room for '\0' */
2618 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2619 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2622 dlen
= datalen
* sizeof(WCHAR
);
2624 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
2625 &dlen
) == ERROR_SUCCESS
) {
2626 if(data
[0] && (data
[1] == ':'))
2628 if((unixname
= wine_get_unix_file_name(data
)))
2630 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2631 HeapFree(GetProcessHeap(), 0, unixname
);
2634 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
2636 WCHAR pathW
[MAX_PATH
];
2637 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2640 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2641 if((unixname
= wine_get_unix_file_name(pathW
)))
2643 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2644 HeapFree(GetProcessHeap(), 0, unixname
);
2647 load_font_from_data_dir(data
);
2649 /* reset dlen and vlen */
2654 HeapFree(GetProcessHeap(), 0, data
);
2655 HeapFree(GetProcessHeap(), 0, valueW
);
2659 load_fontconfig_fonts();
2661 /* then look in any directories that we've specified in the config file */
2662 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2663 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2669 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2671 len
+= sizeof(WCHAR
);
2672 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2673 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2675 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2676 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2677 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2678 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2682 LPSTR next
= strchr( ptr
, ':' );
2683 if (next
) *next
++ = 0;
2684 ReadFontDir( ptr
, TRUE
);
2687 HeapFree( GetProcessHeap(), 0, valueA
);
2689 HeapFree( GetProcessHeap(), 0, valueW
);
2698 update_reg_entries();
2700 init_system_links();
2702 ReleaseMutex(font_mutex
);
2707 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2710 TT_HoriHeader
*pHori
;
2714 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2715 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2717 if(height
== 0) height
= 16;
2719 /* Calc. height of EM square:
2721 * For +ve lfHeight we have
2722 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2723 * Re-arranging gives:
2724 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2726 * For -ve lfHeight we have
2728 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2729 * with il = winAscent + winDescent - units_per_em]
2734 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2735 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2736 pHori
->Ascender
- pHori
->Descender
);
2738 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2739 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2747 static struct font_mapping
*map_font_file( const char *name
)
2749 struct font_mapping
*mapping
;
2753 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2754 if (fstat( fd
, &st
) == -1) goto error
;
2756 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2758 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2760 mapping
->refcount
++;
2765 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2768 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2771 if (mapping
->data
== MAP_FAILED
)
2773 HeapFree( GetProcessHeap(), 0, mapping
);
2776 mapping
->refcount
= 1;
2777 mapping
->dev
= st
.st_dev
;
2778 mapping
->ino
= st
.st_ino
;
2779 mapping
->size
= st
.st_size
;
2780 list_add_tail( &mappings_list
, &mapping
->entry
);
2788 static void unmap_font_file( struct font_mapping
*mapping
)
2790 if (!--mapping
->refcount
)
2792 list_remove( &mapping
->entry
);
2793 munmap( mapping
->data
, mapping
->size
);
2794 HeapFree( GetProcessHeap(), 0, mapping
);
2798 static LONG
load_VDMX(GdiFont
*, LONG
);
2800 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2807 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2811 if (!(font
->mapping
= map_font_file( face
->file
)))
2813 WARN("failed to map %s\n", debugstr_a(face
->file
));
2816 data_ptr
= font
->mapping
->data
;
2817 data_size
= font
->mapping
->size
;
2821 data_ptr
= face
->font_data_ptr
;
2822 data_size
= face
->font_data_size
;
2825 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2827 ERR("FT_New_Face rets %d\n", err
);
2831 /* set it here, as load_VDMX needs it */
2832 font
->ft_face
= ft_face
;
2834 if(FT_IS_SCALABLE(ft_face
)) {
2835 /* load the VDMX table if we have one */
2836 font
->ppem
= load_VDMX(font
, height
);
2838 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2839 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
2841 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2842 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2844 font
->ppem
= height
;
2845 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2846 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2852 static int get_nearest_charset(Face
*face
, int *cp
)
2854 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2855 a single face with the requested charset. The idea is to check if
2856 the selected font supports the current ANSI codepage, if it does
2857 return the corresponding charset, else return the first charset */
2860 int acp
= GetACP(), i
;
2864 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2865 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2866 return csi
.ciCharset
;
2868 for(i
= 0; i
< 32; i
++) {
2870 if(face
->fs
.fsCsb
[0] & fs0
) {
2871 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2873 return csi
.ciCharset
;
2876 FIXME("TCI failing on %x\n", fs0
);
2880 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2881 face
->fs
.fsCsb
[0], face
->file
);
2883 return DEFAULT_CHARSET
;
2886 static GdiFont
*alloc_font(void)
2888 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2890 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2891 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2893 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2894 ret
->total_kern_pairs
= (DWORD
)-1;
2895 ret
->kern_pairs
= NULL
;
2896 list_init(&ret
->hfontlist
);
2897 list_init(&ret
->child_fonts
);
2901 static void free_font(GdiFont
*font
)
2903 struct list
*cursor
, *cursor2
;
2906 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2908 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2909 struct list
*first_hfont
;
2910 HFONTLIST
*hfontlist
;
2911 list_remove(cursor
);
2914 first_hfont
= list_head(&child
->font
->hfontlist
);
2915 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2916 DeleteObject(hfontlist
->hfont
);
2917 HeapFree(GetProcessHeap(), 0, hfontlist
);
2918 free_font(child
->font
);
2920 HeapFree(GetProcessHeap(), 0, child
);
2923 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2924 if (font
->mapping
) unmap_font_file( font
->mapping
);
2925 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2926 HeapFree(GetProcessHeap(), 0, font
->potm
);
2927 HeapFree(GetProcessHeap(), 0, font
->name
);
2928 for (i
= 0; i
< font
->gmsize
; i
++)
2929 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2930 HeapFree(GetProcessHeap(), 0, font
->gm
);
2931 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
2932 HeapFree(GetProcessHeap(), 0, font
);
2936 /*************************************************************
2939 * load the vdmx entry for the specified height
2942 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2943 ( ( (FT_ULong)_x4 << 24 ) | \
2944 ( (FT_ULong)_x3 << 16 ) | \
2945 ( (FT_ULong)_x2 << 8 ) | \
2948 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2963 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2967 BYTE devXRatio
, devYRatio
;
2968 USHORT numRecs
, numRatios
;
2969 DWORD result
, offset
= -1;
2973 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2975 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2978 /* FIXME: need the real device aspect ratio */
2982 numRecs
= GET_BE_WORD(hdr
[1]);
2983 numRatios
= GET_BE_WORD(hdr
[2]);
2985 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2986 for(i
= 0; i
< numRatios
; i
++) {
2989 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2990 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2993 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2995 if((ratio
.xRatio
== 0 &&
2996 ratio
.yStartRatio
== 0 &&
2997 ratio
.yEndRatio
== 0) ||
2998 (devXRatio
== ratio
.xRatio
&&
2999 devYRatio
>= ratio
.yStartRatio
&&
3000 devYRatio
<= ratio
.yEndRatio
))
3002 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3003 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3004 offset
= GET_BE_WORD(tmp
);
3010 FIXME("No suitable ratio found\n");
3014 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3016 BYTE startsz
, endsz
;
3019 recs
= GET_BE_WORD(group
.recs
);
3020 startsz
= group
.startsz
;
3021 endsz
= group
.endsz
;
3023 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3025 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3026 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3027 if(result
== GDI_ERROR
) {
3028 FIXME("Failed to retrieve vTable\n");
3033 for(i
= 0; i
< recs
; i
++) {
3034 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3035 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3036 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3038 if(yMax
+ -yMin
== height
) {
3041 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3044 if(yMax
+ -yMin
> height
) {
3047 goto end
; /* failed */
3049 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3050 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3051 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3052 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3058 TRACE("ppem not found for height %d\n", height
);
3062 if(ppem
< startsz
|| ppem
> endsz
)
3065 for(i
= 0; i
< recs
; i
++) {
3067 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
3069 if(yPelHeight
> ppem
)
3072 if(yPelHeight
== ppem
) {
3073 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3074 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3075 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
3081 HeapFree(GetProcessHeap(), 0, vTable
);
3087 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3089 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3090 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3091 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3092 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3093 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3096 static void calc_hash(FONT_DESC
*pfd
)
3098 DWORD hash
= 0, *ptr
, two_chars
;
3102 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3104 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3106 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3108 pwc
= (WCHAR
*)&two_chars
;
3110 *pwc
= toupperW(*pwc
);
3112 *pwc
= toupperW(*pwc
);
3116 hash
^= !pfd
->can_use_bitmap
;
3121 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3126 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3130 fd
.can_use_bitmap
= can_use_bitmap
;
3133 /* try the child list */
3134 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3135 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3136 if(!fontcmp(ret
, &fd
)) {
3137 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3138 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3139 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3140 if(hflist
->hfont
== hfont
)
3146 /* try the in-use list */
3147 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3148 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3149 if(!fontcmp(ret
, &fd
)) {
3150 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3151 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3152 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3153 if(hflist
->hfont
== hfont
)
3156 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3157 hflist
->hfont
= hfont
;
3158 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3163 /* then the unused list */
3164 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3165 while(font_elem_ptr
) {
3166 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3167 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3168 if(!fontcmp(ret
, &fd
)) {
3169 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3170 assert(list_empty(&ret
->hfontlist
));
3171 TRACE("Found %p in unused list\n", ret
);
3172 list_remove(&ret
->entry
);
3173 list_add_head(&gdi_font_list
, &ret
->entry
);
3174 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3175 hflist
->hfont
= hfont
;
3176 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3183 static void add_to_cache(GdiFont
*font
)
3185 static DWORD cache_num
= 1;
3187 font
->cache_num
= cache_num
++;
3188 list_add_head(&gdi_font_list
, &font
->entry
);
3191 /*************************************************************
3192 * create_child_font_list
3194 static BOOL
create_child_font_list(GdiFont
*font
)
3197 SYSTEM_LINKS
*font_link
;
3198 CHILD_FONT
*font_link_entry
, *new_child
;
3200 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3202 if(!strcmpW(font_link
->font_name
, font
->name
))
3204 TRACE("found entry in system list\n");
3205 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3207 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3208 new_child
->face
= font_link_entry
->face
;
3209 new_child
->font
= NULL
;
3210 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3211 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3218 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3219 * Sans Serif. This is how asian windows get default fallbacks for fonts
3221 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3222 font
->charset
!= OEM_CHARSET
&&
3223 strcmpW(font
->name
,szDefaultFallbackLink
) != 0)
3224 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3226 if(!strcmpW(font_link
->font_name
,szDefaultFallbackLink
))
3228 TRACE("found entry in default fallback list\n");
3229 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3231 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3232 new_child
->face
= font_link_entry
->face
;
3233 new_child
->font
= NULL
;
3234 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3235 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3245 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3247 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3249 if (pFT_Set_Charmap
)
3252 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3254 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3256 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3258 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3260 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3261 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3263 switch (ft_face
->charmaps
[i
]->platform_id
)
3266 cmap_def
= ft_face
->charmaps
[i
];
3268 case 0: /* Apple Unicode */
3269 cmap0
= ft_face
->charmaps
[i
];
3271 case 1: /* Macintosh */
3272 cmap1
= ft_face
->charmaps
[i
];
3275 cmap2
= ft_face
->charmaps
[i
];
3277 case 3: /* Microsoft */
3278 cmap3
= ft_face
->charmaps
[i
];
3283 if (cmap3
) /* prefer Microsoft cmap table */
3284 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3286 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3288 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3290 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3292 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3294 return ft_err
== FT_Err_Ok
;
3297 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3300 /*************************************************************
3301 * WineEngCreateFontInstance
3304 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3307 Face
*face
, *best
, *best_bitmap
;
3308 Family
*family
, *last_resort_family
;
3309 struct list
*family_elem_ptr
, *face_elem_ptr
;
3310 INT height
, width
= 0;
3311 unsigned int score
= 0, new_score
;
3312 signed int diff
= 0, newdiff
;
3313 BOOL bd
, it
, can_use_bitmap
;
3318 FontSubst
*psub
= NULL
;
3320 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3321 lf
.lfWidth
= abs(lf
.lfWidth
);
3323 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3325 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3326 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3327 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3330 if(dc
->GraphicsMode
== GM_ADVANCED
)
3331 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3334 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3335 font scaling abilities. */
3336 dcmat
.eM11
= dcmat
.eM22
= fabs(dc
->xformWorld2Vport
.eM22
);
3337 dcmat
.eM21
= dcmat
.eM12
= 0;
3340 /* Try to avoid not necessary glyph transformations */
3341 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3343 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3344 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3345 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3348 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3349 dcmat
.eM21
, dcmat
.eM22
);
3352 EnterCriticalSection( &freetype_cs
);
3354 /* check the cache first */
3355 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3356 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3357 LeaveCriticalSection( &freetype_cs
);
3361 TRACE("not in cache\n");
3362 if(list_empty(&font_list
)) /* No fonts installed */
3364 TRACE("No fonts installed\n");
3365 LeaveCriticalSection( &freetype_cs
);
3368 if(!have_installed_roman_font
)
3370 TRACE("No roman font installed\n");
3371 LeaveCriticalSection( &freetype_cs
);
3377 ret
->font_desc
.matrix
= dcmat
;
3378 ret
->font_desc
.lf
= lf
;
3379 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3380 calc_hash(&ret
->font_desc
);
3381 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3382 hflist
->hfont
= hfont
;
3383 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3385 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3386 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3387 original value lfCharSet. Note this is a special case for
3388 Symbol and doesn't happen at least for "Wingdings*" */
3390 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3391 lf
.lfCharSet
= SYMBOL_CHARSET
;
3393 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3394 switch(lf
.lfCharSet
) {
3395 case DEFAULT_CHARSET
:
3396 csi
.fs
.fsCsb
[0] = 0;
3399 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3400 csi
.fs
.fsCsb
[0] = 0;
3406 if(lf
.lfFaceName
[0] != '\0') {
3407 SYSTEM_LINKS
*font_link
;
3408 CHILD_FONT
*font_link_entry
;
3409 LPWSTR FaceName
= lf
.lfFaceName
;
3412 * Check for a leading '@' this signals that the font is being
3413 * requested in tategaki mode (vertical writing substitution) but
3414 * does not affect the fontface that is to be selected.
3416 if (lf
.lfFaceName
[0]=='@')
3417 FaceName
= &lf
.lfFaceName
[1];
3419 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3422 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3423 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3424 if (psub
->to
.charset
!= -1)
3425 lf
.lfCharSet
= psub
->to
.charset
;
3428 /* We want a match on name and charset or just name if
3429 charset was DEFAULT_CHARSET. If the latter then
3430 we fixup the returned charset later in get_nearest_charset
3431 where we'll either use the charset of the current ansi codepage
3432 or if that's unavailable the first charset that the font supports.
3434 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3435 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3436 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3437 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3439 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3440 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3441 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3442 if(face
->scalable
|| can_use_bitmap
)
3449 * Try check the SystemLink list first for a replacement font.
3450 * We may find good replacements there.
3452 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3454 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3455 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3457 TRACE("found entry in system list\n");
3458 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3460 face
= font_link_entry
->face
;
3461 family
= face
->family
;
3462 if(csi
.fs
.fsCsb
[0] &
3463 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3465 if(face
->scalable
|| can_use_bitmap
)
3473 psub
= NULL
; /* substitution is no more relevant */
3475 /* If requested charset was DEFAULT_CHARSET then try using charset
3476 corresponding to the current ansi codepage */
3477 if (!csi
.fs
.fsCsb
[0])
3480 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3481 FIXME("TCI failed on codepage %d\n", acp
);
3482 csi
.fs
.fsCsb
[0] = 0;
3484 lf
.lfCharSet
= csi
.ciCharset
;
3487 /* Face families are in the top 4 bits of lfPitchAndFamily,
3488 so mask with 0xF0 before testing */
3490 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3491 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3492 strcpyW(lf
.lfFaceName
, defFixed
);
3493 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3494 strcpyW(lf
.lfFaceName
, defSerif
);
3495 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3496 strcpyW(lf
.lfFaceName
, defSans
);
3498 strcpyW(lf
.lfFaceName
, defSans
);
3499 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3500 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3501 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3502 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3503 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3504 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3505 if(face
->scalable
|| can_use_bitmap
)
3511 last_resort_family
= NULL
;
3512 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3513 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3514 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3515 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3516 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3519 if(can_use_bitmap
&& !last_resort_family
)
3520 last_resort_family
= family
;
3525 if(last_resort_family
) {
3526 family
= last_resort_family
;
3527 csi
.fs
.fsCsb
[0] = 0;
3531 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3532 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3533 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3534 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3535 if(face
->scalable
) {
3536 csi
.fs
.fsCsb
[0] = 0;
3537 WARN("just using first face for now\n");
3540 if(can_use_bitmap
&& !last_resort_family
)
3541 last_resort_family
= family
;
3544 if(!last_resort_family
) {
3545 FIXME("can't find a single appropriate font - bailing\n");
3547 LeaveCriticalSection( &freetype_cs
);
3551 WARN("could only find a bitmap font - this will probably look awful!\n");
3552 family
= last_resort_family
;
3553 csi
.fs
.fsCsb
[0] = 0;
3556 it
= lf
.lfItalic
? 1 : 0;
3557 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3559 height
= lf
.lfHeight
;
3561 face
= best
= best_bitmap
= NULL
;
3562 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3564 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3568 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3569 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3570 new_score
= (italic
^ it
) + (bold
^ bd
);
3571 if(!best
|| new_score
<= score
)
3573 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3574 italic
, bold
, it
, bd
);
3577 if(best
->scalable
&& score
== 0) break;
3581 newdiff
= height
- (signed int)(best
->size
.height
);
3583 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3584 if(!best_bitmap
|| new_score
< score
||
3585 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3587 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3590 if(score
== 0 && diff
== 0) break;
3597 face
= best
->scalable
? best
: best_bitmap
;
3598 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3599 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3603 if(csi
.fs
.fsCsb
[0]) {
3604 ret
->charset
= lf
.lfCharSet
;
3605 ret
->codepage
= csi
.ciACP
;
3608 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3610 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3611 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3613 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3615 if(!face
->scalable
) {
3616 /* Windows uses integer scaling factors for bitmap fonts */
3617 INT scale
, scaled_height
;
3619 /* FIXME: rotation of bitmap fonts is ignored */
3620 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3622 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3623 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3625 if (height
!= 0) height
= diff
;
3626 height
+= face
->size
.height
;
3628 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3629 scaled_height
= scale
* face
->size
.height
;
3630 /* XP allows not more than 10% deviation */
3631 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3632 ret
->scale_y
= scale
;
3634 width
= face
->size
.x_ppem
>> 6;
3635 height
= face
->size
.y_ppem
>> 6;
3639 TRACE("font scale y: %f\n", ret
->scale_y
);
3641 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3646 LeaveCriticalSection( &freetype_cs
);
3650 ret
->ntmFlags
= face
->ntmFlags
;
3652 if (ret
->charset
== SYMBOL_CHARSET
&&
3653 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3656 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3660 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3663 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3664 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3665 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3666 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3667 create_child_font_list(ret
);
3669 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3671 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3672 if (length
!= GDI_ERROR
)
3674 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3675 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3676 TRACE("Loaded GSUB table of %i bytes\n",length
);
3680 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3683 LeaveCriticalSection( &freetype_cs
);
3687 static void dump_gdi_font_list(void)
3690 struct list
*elem_ptr
;
3692 TRACE("---------- gdiFont Cache ----------\n");
3693 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3694 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3695 TRACE("gdiFont=%p %s %d\n",
3696 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3699 TRACE("---------- Unused gdiFont Cache ----------\n");
3700 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3701 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3702 TRACE("gdiFont=%p %s %d\n",
3703 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3707 /*************************************************************
3708 * WineEngDestroyFontInstance
3710 * free the gdiFont associated with this handle
3713 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3718 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3722 EnterCriticalSection( &freetype_cs
);
3724 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3726 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3727 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3728 if(hflist
->hfont
== handle
)
3730 TRACE("removing child font %p from child list\n", gdiFont
);
3731 list_remove(&gdiFont
->entry
);
3732 LeaveCriticalSection( &freetype_cs
);
3737 TRACE("destroying hfont=%p\n", handle
);
3739 dump_gdi_font_list();
3741 font_elem_ptr
= list_head(&gdi_font_list
);
3742 while(font_elem_ptr
) {
3743 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3744 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3746 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3747 while(hfontlist_elem_ptr
) {
3748 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3749 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3750 if(hflist
->hfont
== handle
) {
3751 list_remove(&hflist
->entry
);
3752 HeapFree(GetProcessHeap(), 0, hflist
);
3756 if(list_empty(&gdiFont
->hfontlist
)) {
3757 TRACE("Moving to Unused list\n");
3758 list_remove(&gdiFont
->entry
);
3759 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3764 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3765 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3766 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3767 while(font_elem_ptr
) {
3768 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3769 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3770 TRACE("freeing %p\n", gdiFont
);
3771 list_remove(&gdiFont
->entry
);
3774 LeaveCriticalSection( &freetype_cs
);
3778 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3779 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3784 if (face
->cached_enum_data
)
3787 *pelf
= face
->cached_enum_data
->elf
;
3788 *pntm
= face
->cached_enum_data
->ntm
;
3789 *ptype
= face
->cached_enum_data
->type
;
3793 font
= alloc_font();
3795 if(face
->scalable
) {
3796 height
= -2048; /* 2048 is the most common em size */
3799 height
= face
->size
.y_ppem
>> 6;
3800 width
= face
->size
.x_ppem
>> 6;
3802 font
->scale_y
= 1.0;
3804 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3810 font
->name
= strdupW(face
->family
->FamilyName
);
3811 font
->ntmFlags
= face
->ntmFlags
;
3813 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3815 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3817 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3819 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3820 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3822 lstrcpynW(pelf
->elfFullName
,
3823 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3825 lstrcpynW(pelf
->elfStyle
,
3826 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3831 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3833 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3835 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3836 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3837 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3840 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3841 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3842 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3843 pntm
->ntmFontSig
= face
->fs
;
3845 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3847 pelf
->elfLogFont
.lfEscapement
= 0;
3848 pelf
->elfLogFont
.lfOrientation
= 0;
3849 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3850 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3851 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3852 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3853 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3854 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3855 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3856 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3857 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3858 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3859 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3862 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3863 *ptype
|= TRUETYPE_FONTTYPE
;
3864 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3865 *ptype
|= DEVICE_FONTTYPE
;
3866 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3867 *ptype
|= RASTER_FONTTYPE
;
3869 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3870 if (face
->cached_enum_data
)
3872 face
->cached_enum_data
->elf
= *pelf
;
3873 face
->cached_enum_data
->ntm
= *pntm
;
3874 face
->cached_enum_data
->type
= *ptype
;
3880 /*************************************************************
3884 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3888 struct list
*family_elem_ptr
, *face_elem_ptr
;
3890 NEWTEXTMETRICEXW ntm
;
3899 lf
.lfCharSet
= DEFAULT_CHARSET
;
3900 lf
.lfPitchAndFamily
= 0;
3901 lf
.lfFaceName
[0] = 0;
3905 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3908 EnterCriticalSection( &freetype_cs
);
3909 if(plf
->lfFaceName
[0]) {
3911 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3914 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3915 debugstr_w(psub
->to
.name
));
3917 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3921 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3922 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3923 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3924 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3925 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3926 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3927 for(i
= 0; i
< 32; i
++) {
3928 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3929 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3930 strcpyW(elf
.elfScript
, OEM_DOSW
);
3931 i
= 32; /* break out of loop */
3932 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3935 fs
.fsCsb
[0] = 1L << i
;
3937 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3939 csi
.ciCharset
= DEFAULT_CHARSET
;
3940 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3941 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3942 elf
.elfLogFont
.lfCharSet
=
3943 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3945 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3947 FIXME("Unknown elfscript for bit %d\n", i
);
3950 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3951 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3952 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3953 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3954 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3955 ntm
.ntmTm
.ntmFlags
);
3956 /* release section before callback (FIXME) */
3957 LeaveCriticalSection( &freetype_cs
);
3958 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3959 EnterCriticalSection( &freetype_cs
);
3965 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3966 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3967 face_elem_ptr
= list_head(&family
->faces
);
3968 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3969 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3970 for(i
= 0; i
< 32; i
++) {
3971 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3972 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3973 strcpyW(elf
.elfScript
, OEM_DOSW
);
3974 i
= 32; /* break out of loop */
3975 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3978 fs
.fsCsb
[0] = 1L << i
;
3980 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3982 csi
.ciCharset
= DEFAULT_CHARSET
;
3983 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3984 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3985 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3988 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3990 FIXME("Unknown elfscript for bit %d\n", i
);
3993 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3994 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3995 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3996 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3997 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3998 ntm
.ntmTm
.ntmFlags
);
3999 /* release section before callback (FIXME) */
4000 LeaveCriticalSection( &freetype_cs
);
4001 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
4002 EnterCriticalSection( &freetype_cs
);
4006 LeaveCriticalSection( &freetype_cs
);
4010 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4012 pt
->x
.value
= vec
->x
>> 6;
4013 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4014 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4015 pt
->y
.value
= vec
->y
>> 6;
4016 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4017 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4021 /***************************************************
4022 * According to the MSDN documentation on WideCharToMultiByte,
4023 * certain codepages cannot set the default_used parameter.
4024 * This returns TRUE if the codepage can set that parameter, false else
4025 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4027 static BOOL
codepage_sets_default_used(UINT codepage
)
4041 * GSUB Table handling functions
4044 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4046 const GSUB_CoverageFormat1
* cf1
;
4050 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4052 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4054 TRACE("Coverage Format 1, %i glyphs\n",count
);
4055 for (i
= 0; i
< count
; i
++)
4056 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4060 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4062 const GSUB_CoverageFormat2
* cf2
;
4065 cf2
= (GSUB_CoverageFormat2
*)cf1
;
4067 count
= GET_BE_WORD(cf2
->RangeCount
);
4068 TRACE("Coverage Format 2, %i ranges\n",count
);
4069 for (i
= 0; i
< count
; i
++)
4071 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4073 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4074 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4076 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4077 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4083 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4088 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4090 const GSUB_ScriptList
*script
;
4091 const GSUB_Script
*deflt
= NULL
;
4093 script
= (GSUB_ScriptList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->ScriptList
));
4095 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4096 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4098 const GSUB_Script
*scr
;
4101 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4102 scr
= (GSUB_Script
*)((LPBYTE
)script
+ offset
);
4104 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4106 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4112 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4116 const GSUB_LangSys
*Lang
;
4118 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4120 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4122 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4123 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4125 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4128 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4131 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4137 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4140 const GSUB_FeatureList
*feature
;
4141 feature
= (GSUB_FeatureList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->FeatureList
));
4143 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4144 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4146 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4147 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4149 const GSUB_Feature
*feat
;
4150 feat
= (GSUB_Feature
*)((LPBYTE
)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4157 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4161 const GSUB_LookupList
*lookup
;
4162 lookup
= (GSUB_LookupList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->LookupList
));
4164 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4165 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4167 const GSUB_LookupTable
*look
;
4168 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4169 look
= (GSUB_LookupTable
*)((LPBYTE
)lookup
+ offset
);
4170 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4171 if (GET_BE_WORD(look
->LookupType
) != 1)
4172 FIXME("We only handle SubType 1\n");
4177 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4179 const GSUB_SingleSubstFormat1
*ssf1
;
4180 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4181 ssf1
= (GSUB_SingleSubstFormat1
*)((LPBYTE
)look
+offset
);
4182 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4184 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4185 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4186 if (GSUB_is_glyph_covered((LPBYTE
)ssf1
+offset
, glyph
) != -1)
4188 TRACE(" Glyph 0x%x ->",glyph
);
4189 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4190 TRACE(" 0x%x\n",glyph
);
4195 const GSUB_SingleSubstFormat2
*ssf2
;
4199 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
4200 offset
= GET_BE_WORD(ssf1
->Coverage
);
4201 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4202 index
= GSUB_is_glyph_covered((LPBYTE
)ssf2
+offset
, glyph
);
4203 TRACE(" Coverage index %i\n",index
);
4206 TRACE(" Glyph is 0x%x ->",glyph
);
4207 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4208 TRACE("0x%x\n",glyph
);
4217 static const char* get_opentype_script(const GdiFont
*font
)
4220 * I am not sure if this is the correct way to generate our script tag
4223 switch (font
->charset
)
4225 case ANSI_CHARSET
: return "latn";
4226 case BALTIC_CHARSET
: return "latn"; /* ?? */
4227 case CHINESEBIG5_CHARSET
: return "hani";
4228 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4229 case GB2312_CHARSET
: return "hani";
4230 case GREEK_CHARSET
: return "grek";
4231 case HANGUL_CHARSET
: return "hang";
4232 case RUSSIAN_CHARSET
: return "cyrl";
4233 case SHIFTJIS_CHARSET
: return "kana";
4234 case TURKISH_CHARSET
: return "latn"; /* ?? */
4235 case VIETNAMESE_CHARSET
: return "latn";
4236 case JOHAB_CHARSET
: return "latn"; /* ?? */
4237 case ARABIC_CHARSET
: return "arab";
4238 case HEBREW_CHARSET
: return "hebr";
4239 case THAI_CHARSET
: return "thai";
4240 default: return "latn";
4244 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4246 const GSUB_Header
*header
;
4247 const GSUB_Script
*script
;
4248 const GSUB_LangSys
*language
;
4249 const GSUB_Feature
*feature
;
4251 if (!font
->GSUB_Table
)
4254 header
= font
->GSUB_Table
;
4256 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4259 TRACE("Script not found\n");
4262 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4265 TRACE("Language not found\n");
4268 feature
= GSUB_get_feature(header
, language
, "vrt2");
4270 feature
= GSUB_get_feature(header
, language
, "vert");
4273 TRACE("vrt2/vert feature not found\n");
4276 return GSUB_apply_feature(header
, feature
, glyph
);
4279 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4283 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4284 WCHAR wc
= (WCHAR
)glyph
;
4286 BOOL
*default_used_pointer
;
4289 default_used_pointer
= NULL
;
4290 default_used
= FALSE
;
4291 if (codepage_sets_default_used(font
->codepage
))
4292 default_used_pointer
= &default_used
;
4293 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4296 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4297 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4298 return get_GSUB_vert_glyph(font
,ret
);
4301 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4302 glyph
= glyph
+ 0xf000;
4303 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4304 return get_GSUB_vert_glyph(font
,glyphId
);
4307 /*************************************************************
4308 * WineEngGetGlyphIndices
4311 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4312 LPWORD pgi
, DWORD flags
)
4315 int default_char
= -1;
4317 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4319 for(i
= 0; i
< count
; i
++)
4321 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4324 if (default_char
== -1)
4326 if (FT_IS_SFNT(font
->ft_face
))
4328 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4329 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4334 WineEngGetTextMetrics(font
, &textm
);
4335 default_char
= textm
.tmDefaultChar
;
4338 pgi
[i
] = default_char
;
4344 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4346 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4347 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4350 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4352 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4353 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4356 /*************************************************************
4357 * WineEngGetGlyphOutline
4359 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4360 * except that the first parameter is the HWINEENGFONT of the font in
4361 * question rather than an HDC.
4364 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4365 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4368 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4369 FT_Face ft_face
= incoming_font
->ft_face
;
4370 GdiFont
*font
= incoming_font
;
4371 FT_UInt glyph_index
;
4372 DWORD width
, height
, pitch
, needed
= 0;
4373 FT_Bitmap ft_bitmap
;
4375 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4377 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4378 double widthRatio
= 1.0;
4379 FT_Matrix transMat
= identityMat
;
4380 FT_Matrix transMatUnrotated
;
4381 BOOL needsTransform
= FALSE
;
4382 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4383 UINT original_index
;
4385 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4386 buflen
, buf
, lpmat
);
4388 TRACE("font transform %f %f %f %f\n",
4389 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4390 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4393 EnterCriticalSection( &freetype_cs
);
4395 if(format
& GGO_GLYPH_INDEX
) {
4396 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4397 original_index
= glyph
;
4398 format
&= ~GGO_GLYPH_INDEX
;
4400 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4401 ft_face
= font
->ft_face
;
4402 original_index
= glyph_index
;
4405 if(format
& GGO_UNHINTED
) {
4406 load_flags
|= FT_LOAD_NO_HINTING
;
4407 format
&= ~GGO_UNHINTED
;
4410 /* tategaki never appears to happen to lower glyph index */
4411 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4414 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4415 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4416 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4417 font
->gmsize
* sizeof(GM
*));
4419 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4420 FONT_GM(font
,original_index
)->init
&& (!lpmat
|| is_identity_MAT2(lpmat
)))
4422 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4423 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4424 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4425 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4426 LeaveCriticalSection( &freetype_cs
);
4427 return 1; /* FIXME */
4431 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4432 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4434 /* Scaling factor */
4439 WineEngGetTextMetrics(font
, &tm
);
4441 widthRatio
= (double)font
->aveWidth
;
4442 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4445 widthRatio
= font
->scale_y
;
4447 /* Scaling transform */
4448 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4451 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4454 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4456 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4457 needsTransform
= TRUE
;
4460 /* Slant transform */
4461 if (font
->fake_italic
) {
4464 slantMat
.xx
= (1 << 16);
4465 slantMat
.xy
= ((1 << 16) >> 2);
4467 slantMat
.yy
= (1 << 16);
4468 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4469 needsTransform
= TRUE
;
4472 /* Rotation transform */
4473 transMatUnrotated
= transMat
;
4474 if(font
->orientation
&& !tategaki
) {
4475 FT_Matrix rotationMat
;
4477 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4478 pFT_Vector_Unit(&vecAngle
, angle
);
4479 rotationMat
.xx
= vecAngle
.x
;
4480 rotationMat
.xy
= -vecAngle
.y
;
4481 rotationMat
.yx
= -rotationMat
.xy
;
4482 rotationMat
.yy
= rotationMat
.xx
;
4484 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4485 needsTransform
= TRUE
;
4488 /* World transform */
4489 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4492 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4493 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4494 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4495 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4496 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4497 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4498 needsTransform
= TRUE
;
4501 /* Extra transformation specified by caller */
4502 if (lpmat
&& !is_identity_MAT2(lpmat
))
4505 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4506 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
4507 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
4508 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4509 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4510 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4511 needsTransform
= TRUE
;
4514 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4515 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4516 format
== GGO_GRAY8_BITMAP
))
4518 load_flags
|= FT_LOAD_NO_BITMAP
;
4521 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4524 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4525 LeaveCriticalSection( &freetype_cs
);
4529 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4530 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4532 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
) + 63) >> 6;
4534 bbx
= (right
- left
) >> 6;
4536 if(!needsTransform
) {
4537 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4538 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4539 ft_face
->glyph
->metrics
.height
) & -64;
4540 lpgm
->gmCellIncX
= adv
;
4541 lpgm
->gmCellIncY
= 0;
4545 for(xc
= 0; xc
< 2; xc
++) {
4546 for(yc
= 0; yc
< 2; yc
++) {
4547 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4548 xc
* ft_face
->glyph
->metrics
.width
);
4549 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4550 yc
* ft_face
->glyph
->metrics
.height
;
4551 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4552 pFT_Vector_Transform(&vec
, &transMat
);
4553 if(xc
== 0 && yc
== 0) {
4554 left
= right
= vec
.x
;
4555 top
= bottom
= vec
.y
;
4557 if(vec
.x
< left
) left
= vec
.x
;
4558 else if(vec
.x
> right
) right
= vec
.x
;
4559 if(vec
.y
< bottom
) bottom
= vec
.y
;
4560 else if(vec
.y
> top
) top
= vec
.y
;
4565 right
= (right
+ 63) & -64;
4566 bottom
= bottom
& -64;
4567 top
= (top
+ 63) & -64;
4569 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4570 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4572 pFT_Vector_Transform(&vec
, &transMat
);
4573 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4574 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4576 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4578 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4579 adv
= (vec
.x
+63) >> 6;
4581 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4582 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4583 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4584 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4586 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4587 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4588 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4590 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4591 (!lpmat
|| is_identity_MAT2(lpmat
))) /* don't cache custom transforms */
4593 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4594 FONT_GM(font
,original_index
)->adv
= adv
;
4595 FONT_GM(font
,original_index
)->lsb
= lsb
;
4596 FONT_GM(font
,original_index
)->bbx
= bbx
;
4597 FONT_GM(font
,original_index
)->init
= TRUE
;
4600 if(format
== GGO_METRICS
)
4602 LeaveCriticalSection( &freetype_cs
);
4603 return 1; /* FIXME */
4606 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
4607 (needsTransform
|| format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4608 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4609 format
== GGO_GRAY8_BITMAP
))
4611 TRACE("loaded a bitmap\n");
4612 LeaveCriticalSection( &freetype_cs
);
4618 width
= lpgm
->gmBlackBoxX
;
4619 height
= lpgm
->gmBlackBoxY
;
4620 pitch
= ((width
+ 31) >> 5) << 2;
4621 needed
= pitch
* height
;
4623 if(!buf
|| !buflen
) break;
4625 switch(ft_face
->glyph
->format
) {
4626 case ft_glyph_format_bitmap
:
4628 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4629 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4630 INT h
= ft_face
->glyph
->bitmap
.rows
;
4632 memcpy(dst
, src
, w
);
4633 src
+= ft_face
->glyph
->bitmap
.pitch
;
4639 case ft_glyph_format_outline
:
4640 ft_bitmap
.width
= width
;
4641 ft_bitmap
.rows
= height
;
4642 ft_bitmap
.pitch
= pitch
;
4643 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4644 ft_bitmap
.buffer
= buf
;
4647 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4649 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4651 /* Note: FreeType will only set 'black' bits for us. */
4652 memset(buf
, 0, needed
);
4653 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4657 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4658 LeaveCriticalSection( &freetype_cs
);
4663 case GGO_GRAY2_BITMAP
:
4664 case GGO_GRAY4_BITMAP
:
4665 case GGO_GRAY8_BITMAP
:
4666 case WINE_GGO_GRAY16_BITMAP
:
4668 unsigned int mult
, row
, col
;
4671 width
= lpgm
->gmBlackBoxX
;
4672 height
= lpgm
->gmBlackBoxY
;
4673 pitch
= (width
+ 3) / 4 * 4;
4674 needed
= pitch
* height
;
4676 if(!buf
|| !buflen
) break;
4678 switch(ft_face
->glyph
->format
) {
4679 case ft_glyph_format_bitmap
:
4681 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4682 INT h
= ft_face
->glyph
->bitmap
.rows
;
4685 for(x
= 0; x
< pitch
; x
++)
4687 if(x
< ft_face
->glyph
->bitmap
.width
)
4688 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4692 src
+= ft_face
->glyph
->bitmap
.pitch
;
4695 LeaveCriticalSection( &freetype_cs
);
4698 case ft_glyph_format_outline
:
4700 ft_bitmap
.width
= width
;
4701 ft_bitmap
.rows
= height
;
4702 ft_bitmap
.pitch
= pitch
;
4703 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4704 ft_bitmap
.buffer
= buf
;
4707 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4709 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4711 memset(ft_bitmap
.buffer
, 0, buflen
);
4713 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4715 if(format
== GGO_GRAY2_BITMAP
)
4717 else if(format
== GGO_GRAY4_BITMAP
)
4719 else if(format
== GGO_GRAY8_BITMAP
)
4721 else /* format == WINE_GGO_GRAY16_BITMAP */
4723 LeaveCriticalSection( &freetype_cs
);
4729 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4730 LeaveCriticalSection( &freetype_cs
);
4735 for(row
= 0; row
< height
; row
++) {
4737 for(col
= 0; col
< width
; col
++, ptr
++) {
4738 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4745 case WINE_GGO_HRGB_BITMAP
:
4746 case WINE_GGO_HBGR_BITMAP
:
4747 case WINE_GGO_VRGB_BITMAP
:
4748 case WINE_GGO_VBGR_BITMAP
:
4749 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4751 switch (ft_face
->glyph
->format
)
4753 case FT_GLYPH_FORMAT_BITMAP
:
4758 width
= lpgm
->gmBlackBoxX
;
4759 height
= lpgm
->gmBlackBoxY
;
4761 needed
= pitch
* height
;
4763 if (!buf
|| !buflen
) break;
4765 memset(buf
, 0, buflen
);
4767 src
= ft_face
->glyph
->bitmap
.buffer
;
4768 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
4772 for (x
= 0; x
< width
; x
++)
4774 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
4775 ((unsigned int *)dst
)[x
] = ~0u;
4784 case FT_GLYPH_FORMAT_OUTLINE
:
4788 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
4789 INT x_shift
, y_shift
;
4791 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
4792 FT_Render_Mode render_mode
=
4793 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
4794 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
4796 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
4798 if ( render_mode
== FT_RENDER_MODE_LCD
)
4800 lpgm
->gmBlackBoxX
+= 2;
4801 lpgm
->gmptGlyphOrigin
.x
-= 1;
4805 lpgm
->gmBlackBoxY
+= 2;
4806 lpgm
->gmptGlyphOrigin
.y
+= 1;
4810 width
= lpgm
->gmBlackBoxX
;
4811 height
= lpgm
->gmBlackBoxY
;
4813 needed
= pitch
* height
;
4815 if (!buf
|| !buflen
) break;
4817 memset(buf
, 0, buflen
);
4819 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
4821 if ( needsTransform
)
4822 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
4824 if ( pFT_Library_SetLcdFilter
)
4825 pFT_Library_SetLcdFilter( library
, lcdfilter
);
4826 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
4828 src
= ft_face
->glyph
->bitmap
.buffer
;
4829 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
4830 src_width
= ft_face
->glyph
->bitmap
.width
;
4831 src_height
= ft_face
->glyph
->bitmap
.rows
;
4833 if ( render_mode
== FT_RENDER_MODE_LCD
)
4841 rgb_interval
= src_pitch
;
4846 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
4847 if ( x_shift
< 0 ) x_shift
= 0;
4848 if ( x_shift
+ (src_width
/ hmul
) > width
)
4849 x_shift
= width
- (src_width
/ hmul
);
4851 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
4852 if ( y_shift
< 0 ) y_shift
= 0;
4853 if ( y_shift
+ (src_height
/ vmul
) > height
)
4854 y_shift
= height
- (src_height
/ vmul
);
4856 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
4857 while ( src_height
)
4859 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
4863 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
4864 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
4865 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
4866 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
4870 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
4871 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
4872 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
4873 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
4876 src
+= src_pitch
* vmul
;
4885 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
4886 LeaveCriticalSection ( &freetype_cs
);
4893 LeaveCriticalSection( &freetype_cs
);
4899 int contour
, point
= 0, first_pt
;
4900 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4901 TTPOLYGONHEADER
*pph
;
4903 DWORD pph_start
, cpfx
, type
;
4905 if(buflen
== 0) buf
= NULL
;
4907 if (needsTransform
&& buf
) {
4908 pFT_Outline_Transform(outline
, &transMat
);
4911 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4913 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4916 pph
->dwType
= TT_POLYGON_TYPE
;
4917 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4919 needed
+= sizeof(*pph
);
4921 while(point
<= outline
->contours
[contour
]) {
4922 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4923 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4924 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4928 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4931 } while(point
<= outline
->contours
[contour
] &&
4932 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4933 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4934 /* At the end of a contour Windows adds the start point, but
4936 if(point
> outline
->contours
[contour
] &&
4937 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4939 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4941 } else if(point
<= outline
->contours
[contour
] &&
4942 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4943 /* add closing pt for bezier */
4945 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4953 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4956 pph
->cb
= needed
- pph_start
;
4962 /* Convert the quadratic Beziers to cubic Beziers.
4963 The parametric eqn for a cubic Bezier is, from PLRM:
4964 r(t) = at^3 + bt^2 + ct + r0
4965 with the control points:
4970 A quadratic Beizer has the form:
4971 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4973 So equating powers of t leads to:
4974 r1 = 2/3 p1 + 1/3 p0
4975 r2 = 2/3 p1 + 1/3 p2
4976 and of course r0 = p0, r3 = p2
4979 int contour
, point
= 0, first_pt
;
4980 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4981 TTPOLYGONHEADER
*pph
;
4983 DWORD pph_start
, cpfx
, type
;
4984 FT_Vector cubic_control
[4];
4985 if(buflen
== 0) buf
= NULL
;
4987 if (needsTransform
&& buf
) {
4988 pFT_Outline_Transform(outline
, &transMat
);
4991 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4993 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4996 pph
->dwType
= TT_POLYGON_TYPE
;
4997 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4999 needed
+= sizeof(*pph
);
5001 while(point
<= outline
->contours
[contour
]) {
5002 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5003 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5004 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5007 if(type
== TT_PRIM_LINE
) {
5009 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5013 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5016 /* FIXME: Possible optimization in endpoint calculation
5017 if there are two consecutive curves */
5018 cubic_control
[0] = outline
->points
[point
-1];
5019 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5020 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5021 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5022 cubic_control
[0].x
>>= 1;
5023 cubic_control
[0].y
>>= 1;
5025 if(point
+1 > outline
->contours
[contour
])
5026 cubic_control
[3] = outline
->points
[first_pt
];
5028 cubic_control
[3] = outline
->points
[point
+1];
5029 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5030 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5031 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5032 cubic_control
[3].x
>>= 1;
5033 cubic_control
[3].y
>>= 1;
5036 /* r1 = 1/3 p0 + 2/3 p1
5037 r2 = 1/3 p2 + 2/3 p1 */
5038 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5039 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5040 cubic_control
[2] = cubic_control
[1];
5041 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5042 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5043 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5044 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5046 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5047 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5048 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5053 } while(point
<= outline
->contours
[contour
] &&
5054 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5055 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5056 /* At the end of a contour Windows adds the start point,
5057 but only for Beziers and we've already done that.
5059 if(point
<= outline
->contours
[contour
] &&
5060 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5061 /* This is the closing pt of a bezier, but we've already
5062 added it, so just inc point and carry on */
5069 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5072 pph
->cb
= needed
- pph_start
;
5078 FIXME("Unsupported format %d\n", format
);
5079 LeaveCriticalSection( &freetype_cs
);
5082 LeaveCriticalSection( &freetype_cs
);
5086 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5088 FT_Face ft_face
= font
->ft_face
;
5089 #ifdef HAVE_FREETYPE_FTWINFNT_H
5090 FT_WinFNT_HeaderRec winfnt_header
;
5092 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5093 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5094 font
->potm
->otmSize
= size
;
5096 #define TM font->potm->otmTextMetrics
5097 #ifdef HAVE_FREETYPE_FTWINFNT_H
5098 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5100 TM
.tmHeight
= winfnt_header
.pixel_height
;
5101 TM
.tmAscent
= winfnt_header
.ascent
;
5102 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5103 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5104 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5105 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5106 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5107 TM
.tmWeight
= winfnt_header
.weight
;
5109 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5110 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5111 TM
.tmFirstChar
= winfnt_header
.first_char
;
5112 TM
.tmLastChar
= winfnt_header
.last_char
;
5113 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5114 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5115 TM
.tmItalic
= winfnt_header
.italic
;
5116 TM
.tmUnderlined
= font
->underline
;
5117 TM
.tmStruckOut
= font
->strikeout
;
5118 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5119 TM
.tmCharSet
= winfnt_header
.charset
;
5124 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5125 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5126 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5127 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5128 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5129 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5130 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5131 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5133 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5134 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5136 TM
.tmLastChar
= 255;
5137 TM
.tmDefaultChar
= 32;
5138 TM
.tmBreakChar
= 32;
5139 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5140 TM
.tmUnderlined
= font
->underline
;
5141 TM
.tmStruckOut
= font
->strikeout
;
5142 /* NB inverted meaning of TMPF_FIXED_PITCH */
5143 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5144 TM
.tmCharSet
= font
->charset
;
5152 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5154 double scale_x
, scale_y
;
5158 scale_x
= (double)font
->aveWidth
;
5159 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5162 scale_x
= font
->scale_y
;
5164 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5165 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5167 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5168 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5170 SCALE_Y(ptm
->tmHeight
);
5171 SCALE_Y(ptm
->tmAscent
);
5172 SCALE_Y(ptm
->tmDescent
);
5173 SCALE_Y(ptm
->tmInternalLeading
);
5174 SCALE_Y(ptm
->tmExternalLeading
);
5175 SCALE_Y(ptm
->tmOverhang
);
5177 SCALE_X(ptm
->tmAveCharWidth
);
5178 SCALE_X(ptm
->tmMaxCharWidth
);
5184 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5186 double scale_x
, scale_y
;
5190 scale_x
= (double)font
->aveWidth
;
5191 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5194 scale_x
= font
->scale_y
;
5196 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5197 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5199 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5201 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5202 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5204 SCALE_Y(potm
->otmAscent
);
5205 SCALE_Y(potm
->otmDescent
);
5206 SCALE_Y(potm
->otmLineGap
);
5207 SCALE_Y(potm
->otmsCapEmHeight
);
5208 SCALE_Y(potm
->otmsXHeight
);
5209 SCALE_Y(potm
->otmrcFontBox
.top
);
5210 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5211 SCALE_X(potm
->otmrcFontBox
.left
);
5212 SCALE_X(potm
->otmrcFontBox
.right
);
5213 SCALE_Y(potm
->otmMacAscent
);
5214 SCALE_Y(potm
->otmMacDescent
);
5215 SCALE_Y(potm
->otmMacLineGap
);
5216 SCALE_X(potm
->otmptSubscriptSize
.x
);
5217 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5218 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5219 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5220 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5221 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5222 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5223 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5224 SCALE_Y(potm
->otmsStrikeoutSize
);
5225 SCALE_Y(potm
->otmsStrikeoutPosition
);
5226 SCALE_Y(potm
->otmsUnderscoreSize
);
5227 SCALE_Y(potm
->otmsUnderscorePosition
);
5233 /*************************************************************
5234 * WineEngGetTextMetrics
5237 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5240 EnterCriticalSection( &freetype_cs
);
5242 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5243 if(!get_bitmap_text_metrics(font
))
5245 LeaveCriticalSection( &freetype_cs
);
5251 LeaveCriticalSection( &freetype_cs
);
5254 *ptm
= font
->potm
->otmTextMetrics
;
5255 scale_font_metrics(font
, ptm
);
5256 LeaveCriticalSection( &freetype_cs
);
5261 /*************************************************************
5262 * WineEngGetOutlineTextMetrics
5265 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5266 OUTLINETEXTMETRICW
*potm
)
5268 FT_Face ft_face
= font
->ft_face
;
5269 UINT needed
, lenfam
, lensty
, ret
;
5271 TT_HoriHeader
*pHori
;
5272 TT_Postscript
*pPost
;
5273 FT_Fixed x_scale
, y_scale
;
5274 WCHAR
*family_nameW
, *style_nameW
;
5275 static const WCHAR spaceW
[] = {' ', '\0'};
5277 INT ascent
, descent
;
5279 TRACE("font=%p\n", font
);
5281 if(!FT_IS_SCALABLE(ft_face
))
5285 EnterCriticalSection( &freetype_cs
);
5288 if(cbSize
>= font
->potm
->otmSize
)
5290 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5291 scale_outline_font_metrics(font
, potm
);
5293 LeaveCriticalSection( &freetype_cs
);
5294 return font
->potm
->otmSize
;
5298 needed
= sizeof(*potm
);
5300 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5301 family_nameW
= strdupW(font
->name
);
5303 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5305 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5306 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5307 style_nameW
, lensty
/sizeof(WCHAR
));
5309 /* These names should be read from the TT name table */
5311 /* length of otmpFamilyName */
5314 /* length of otmpFaceName */
5315 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5316 needed
+= lenfam
; /* just the family name */
5318 needed
+= lenfam
+ lensty
; /* family + " " + style */
5321 /* length of otmpStyleName */
5324 /* length of otmpFullName */
5325 needed
+= lenfam
+ lensty
;
5328 x_scale
= ft_face
->size
->metrics
.x_scale
;
5329 y_scale
= ft_face
->size
->metrics
.y_scale
;
5331 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5333 FIXME("Can't find OS/2 table - not TT font?\n");
5338 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5340 FIXME("Can't find HHEA table - not TT font?\n");
5345 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5347 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",
5348 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5349 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5350 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5351 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5352 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5354 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5355 font
->potm
->otmSize
= needed
;
5357 #define TM font->potm->otmTextMetrics
5359 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5360 ascent
= pHori
->Ascender
;
5361 descent
= -pHori
->Descender
;
5363 ascent
= pOS2
->usWinAscent
;
5364 descent
= pOS2
->usWinDescent
;
5368 TM
.tmAscent
= font
->yMax
;
5369 TM
.tmDescent
= -font
->yMin
;
5370 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5372 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5373 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5374 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5375 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5378 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5381 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5383 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5384 ((ascent
+ descent
) -
5385 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5387 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5388 if (TM
.tmAveCharWidth
== 0) {
5389 TM
.tmAveCharWidth
= 1;
5391 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5392 TM
.tmWeight
= (font
->fake_bold
|| (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)) ? FW_BOLD
: FW_REGULAR
;
5394 TM
.tmDigitizedAspectX
= 300;
5395 TM
.tmDigitizedAspectY
= 300;
5396 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5397 * symbol range to 0 - f0ff
5399 if (font
->charset
== SYMBOL_CHARSET
)
5402 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
5406 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
5407 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0xffff;
5409 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
5410 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
5411 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5412 TM
.tmUnderlined
= font
->underline
;
5413 TM
.tmStruckOut
= font
->strikeout
;
5415 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5416 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5417 (pOS2
->version
== 0xFFFFU
||
5418 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5419 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5421 TM
.tmPitchAndFamily
= 0;
5423 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
5424 case PAN_FAMILY_SCRIPT
:
5425 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5427 case PAN_FAMILY_DECORATIVE
:
5428 case PAN_FAMILY_PICTORIAL
:
5429 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5431 case PAN_FAMILY_TEXT_DISPLAY
:
5432 if(TM
.tmPitchAndFamily
== 0) /* fixed */
5433 TM
.tmPitchAndFamily
= FF_MODERN
;
5435 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
5436 case PAN_SERIF_NORMAL_SANS
:
5437 case PAN_SERIF_OBTUSE_SANS
:
5438 case PAN_SERIF_PERP_SANS
:
5439 TM
.tmPitchAndFamily
|= FF_SWISS
;
5442 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5447 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5450 if(FT_IS_SCALABLE(ft_face
))
5451 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5453 if(FT_IS_SFNT(ft_face
))
5455 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5456 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5458 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5461 TM
.tmCharSet
= font
->charset
;
5463 font
->potm
->otmFiller
= 0;
5464 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5465 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5466 font
->potm
->otmfsType
= pOS2
->fsType
;
5467 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5468 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5469 font
->potm
->otmItalicAngle
= 0; /* POST table */
5470 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5471 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5472 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5473 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5474 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5475 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5476 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5477 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5478 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5479 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5480 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5481 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5482 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5483 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5484 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5485 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5486 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5487 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5488 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5489 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5490 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5491 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5492 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5493 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5495 font
->potm
->otmsUnderscoreSize
= 0;
5496 font
->potm
->otmsUnderscorePosition
= 0;
5498 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5499 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5503 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5504 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5505 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5506 strcpyW((WCHAR
*)cp
, family_nameW
);
5508 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5509 strcpyW((WCHAR
*)cp
, style_nameW
);
5511 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5512 strcpyW((WCHAR
*)cp
, family_nameW
);
5513 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5514 strcatW((WCHAR
*)cp
, spaceW
);
5515 strcatW((WCHAR
*)cp
, style_nameW
);
5516 cp
+= lenfam
+ lensty
;
5519 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5520 strcpyW((WCHAR
*)cp
, family_nameW
);
5521 strcatW((WCHAR
*)cp
, spaceW
);
5522 strcatW((WCHAR
*)cp
, style_nameW
);
5525 if(potm
&& needed
<= cbSize
)
5527 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5528 scale_outline_font_metrics(font
, potm
);
5532 HeapFree(GetProcessHeap(), 0, style_nameW
);
5533 HeapFree(GetProcessHeap(), 0, family_nameW
);
5535 LeaveCriticalSection( &freetype_cs
);
5539 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5541 HFONTLIST
*hfontlist
;
5542 child
->font
= alloc_font();
5543 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5544 if(!child
->font
->ft_face
)
5546 free_font(child
->font
);
5551 child
->font
->font_desc
= font
->font_desc
;
5552 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5553 child
->font
->orientation
= font
->orientation
;
5554 child
->font
->scale_y
= font
->scale_y
;
5555 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5556 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5557 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5558 child
->font
->base_font
= font
;
5559 list_add_head(&child_font_list
, &child
->font
->entry
);
5560 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5564 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5567 CHILD_FONT
*child_font
;
5570 font
= font
->base_font
;
5572 *linked_font
= font
;
5574 if((*glyph
= get_glyph_index(font
, c
)))
5577 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5579 if(!child_font
->font
)
5580 if(!load_child_font(font
, child_font
))
5583 if(!child_font
->font
->ft_face
)
5585 g
= get_glyph_index(child_font
->font
, c
);
5589 *linked_font
= child_font
->font
;
5596 /*************************************************************
5597 * WineEngGetCharWidth
5600 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5605 FT_UInt glyph_index
;
5606 GdiFont
*linked_font
;
5608 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5611 EnterCriticalSection( &freetype_cs
);
5612 for(c
= firstChar
; c
<= lastChar
; c
++) {
5613 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5614 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5615 &gm
, 0, NULL
, NULL
);
5616 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5618 LeaveCriticalSection( &freetype_cs
);
5622 /*************************************************************
5623 * WineEngGetCharABCWidths
5626 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5631 FT_UInt glyph_index
;
5632 GdiFont
*linked_font
;
5634 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5636 if(!FT_IS_SCALABLE(font
->ft_face
))
5640 EnterCriticalSection( &freetype_cs
);
5642 for(c
= firstChar
; c
<= lastChar
; c
++) {
5643 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5644 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5645 &gm
, 0, NULL
, NULL
);
5646 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5647 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5648 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5649 FONT_GM(linked_font
,glyph_index
)->bbx
;
5651 LeaveCriticalSection( &freetype_cs
);
5655 /*************************************************************
5656 * WineEngGetCharABCWidthsI
5659 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5664 FT_UInt glyph_index
;
5665 GdiFont
*linked_font
;
5667 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5671 EnterCriticalSection( &freetype_cs
);
5673 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5675 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5676 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5677 &gm
, 0, NULL
, NULL
);
5678 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5679 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5680 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5681 - FONT_GM(linked_font
,c
)->bbx
;
5684 for(c
= 0; c
< count
; c
++) {
5685 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5686 &gm
, 0, NULL
, NULL
);
5687 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5688 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5689 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5690 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5693 LeaveCriticalSection( &freetype_cs
);
5697 /*************************************************************
5698 * WineEngGetTextExtentExPoint
5701 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5702 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5708 FT_UInt glyph_index
;
5709 GdiFont
*linked_font
;
5711 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
5715 EnterCriticalSection( &freetype_cs
);
5718 WineEngGetTextMetrics(font
, &tm
);
5719 size
->cy
= tm
.tmHeight
;
5721 for(idx
= 0; idx
< count
; idx
++) {
5722 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
5723 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5724 &gm
, 0, NULL
, NULL
);
5725 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
5727 if (! pnfit
|| ext
<= max_ext
) {
5737 LeaveCriticalSection( &freetype_cs
);
5738 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5742 /*************************************************************
5743 * WineEngGetTextExtentExPointI
5746 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5747 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5754 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
5757 EnterCriticalSection( &freetype_cs
);
5760 WineEngGetTextMetrics(font
, &tm
);
5761 size
->cy
= tm
.tmHeight
;
5763 for(idx
= 0; idx
< count
; idx
++) {
5764 WineEngGetGlyphOutline(font
, indices
[idx
],
5765 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
5767 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
5769 if (! pnfit
|| ext
<= max_ext
) {
5779 LeaveCriticalSection( &freetype_cs
);
5780 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5784 /*************************************************************
5785 * WineEngGetFontData
5788 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5791 FT_Face ft_face
= font
->ft_face
;
5795 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5796 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
5797 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
5799 if(!FT_IS_SFNT(ft_face
))
5807 if(table
) { /* MS tags differ in endianness from FT ones */
5808 table
= table
>> 24 | table
<< 24 |
5809 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
5812 /* make sure value of len is the value freetype says it needs */
5815 FT_ULong needed
= 0;
5816 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
5817 if( !err
&& needed
< len
) len
= needed
;
5819 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
5822 TRACE("Can't find table %c%c%c%c\n",
5823 /* bytes were reversed */
5824 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
5825 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
5831 /*************************************************************
5832 * WineEngGetTextFace
5835 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5837 INT n
= strlenW(font
->name
) + 1;
5839 lstrcpynW(str
, font
->name
, count
);
5840 return min(count
, n
);
5845 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5847 if (fs
) *fs
= font
->fs
;
5848 return font
->charset
;
5851 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5853 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
5854 struct list
*first_hfont
;
5858 EnterCriticalSection( &freetype_cs
);
5859 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
5860 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
5861 if(font
== linked_font
)
5862 *new_hfont
= dc
->hFont
;
5865 first_hfont
= list_head(&linked_font
->hfontlist
);
5866 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
5868 LeaveCriticalSection( &freetype_cs
);
5872 /* Retrieve a list of supported Unicode ranges for a given font.
5873 * Can be called with NULL gs to calculate the buffer size. Returns
5874 * the number of ranges found.
5876 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
5878 DWORD num_ranges
= 0;
5880 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5883 FT_ULong char_code
, char_code_prev
;
5886 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
5888 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5889 face
->num_glyphs
, glyph_code
, char_code
);
5891 if (!glyph_code
) return 0;
5895 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
5896 gs
->ranges
[0].cGlyphs
= 0;
5897 gs
->cGlyphsSupported
= 0;
5903 if (char_code
< char_code_prev
)
5905 ERR("expected increasing char code from FT_Get_Next_Char\n");
5908 if (char_code
- char_code_prev
> 1)
5913 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
5914 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
5915 gs
->cGlyphsSupported
++;
5920 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
5921 gs
->cGlyphsSupported
++;
5923 char_code_prev
= char_code
;
5924 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
5928 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
5933 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5936 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
5938 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
5941 glyphset
->cbThis
= size
;
5942 glyphset
->cRanges
= num_ranges
;
5947 /*************************************************************
5950 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5954 EnterCriticalSection( &freetype_cs
);
5955 ret
= !list_empty(&font
->child_fonts
);
5956 LeaveCriticalSection( &freetype_cs
);
5960 static BOOL
is_hinting_enabled(void)
5962 /* Use the >= 2.2.0 function if available */
5963 if(pFT_Get_TrueType_Engine_Type
)
5965 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
5966 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
5968 #ifdef FT_DRIVER_HAS_HINTER
5973 /* otherwise if we've been compiled with < 2.2.0 headers
5974 use the internal macro */
5975 mod
= pFT_Get_Module(library
, "truetype");
5976 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
5984 static BOOL
is_subpixel_rendering_enabled( void )
5986 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5987 return pFT_Library_SetLcdFilter
&&
5988 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
5994 /*************************************************************************
5995 * GetRasterizerCaps (GDI32.@)
5997 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5999 static int hinting
= -1;
6000 static int subpixel
= -1;
6004 hinting
= is_hinting_enabled();
6005 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6008 if ( subpixel
== -1 )
6010 subpixel
= is_subpixel_rendering_enabled();
6011 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6014 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6015 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6017 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6018 lprs
->nLanguageID
= 0;
6022 /*************************************************************
6023 * WineEngRealizationInfo
6025 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6027 FIXME("(%p, %p): stub!\n", font
, info
);
6030 if(FT_IS_SCALABLE(font
->ft_face
))
6033 info
->cache_num
= font
->cache_num
;
6034 info
->unknown2
= -1;
6038 /*************************************************************************
6039 * Kerning support for TrueType fonts
6041 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6043 struct TT_kern_table
6049 struct TT_kern_subtable
6058 USHORT horizontal
: 1;
6060 USHORT cross_stream
: 1;
6061 USHORT override
: 1;
6062 USHORT reserved1
: 4;
6068 struct TT_format0_kern_subtable
6072 USHORT entrySelector
;
6083 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6084 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6085 const USHORT
*glyph_to_char
,
6086 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6089 const struct TT_kern_pair
*tt_kern_pair
;
6091 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6093 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6095 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6096 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6097 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6099 if (!kern_pair
|| !cPairs
)
6102 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6104 nPairs
= min(nPairs
, cPairs
);
6106 for (i
= 0; i
< nPairs
; i
++)
6108 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6109 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6110 /* this algorithm appears to better match what Windows does */
6111 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6112 if (kern_pair
->iKernAmount
< 0)
6114 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6115 kern_pair
->iKernAmount
-= font
->ppem
;
6117 else if (kern_pair
->iKernAmount
> 0)
6119 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6120 kern_pair
->iKernAmount
+= font
->ppem
;
6122 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6124 TRACE("left %u right %u value %d\n",
6125 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6129 TRACE("copied %u entries\n", nPairs
);
6133 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6137 const struct TT_kern_table
*tt_kern_table
;
6138 const struct TT_kern_subtable
*tt_kern_subtable
;
6140 USHORT
*glyph_to_char
;
6143 EnterCriticalSection( &freetype_cs
);
6144 if (font
->total_kern_pairs
!= (DWORD
)-1)
6146 if (cPairs
&& kern_pair
)
6148 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6149 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6150 LeaveCriticalSection( &freetype_cs
);
6153 LeaveCriticalSection( &freetype_cs
);
6154 return font
->total_kern_pairs
;
6157 font
->total_kern_pairs
= 0;
6159 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6161 if (length
== GDI_ERROR
)
6163 TRACE("no kerning data in the font\n");
6164 LeaveCriticalSection( &freetype_cs
);
6168 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6171 WARN("Out of memory\n");
6172 LeaveCriticalSection( &freetype_cs
);
6176 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6178 /* build a glyph index to char code map */
6179 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6182 WARN("Out of memory allocating a glyph index to char code map\n");
6183 HeapFree(GetProcessHeap(), 0, buf
);
6184 LeaveCriticalSection( &freetype_cs
);
6188 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6194 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6196 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6197 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6201 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6203 /* FIXME: This doesn't match what Windows does: it does some fancy
6204 * things with duplicate glyph index to char code mappings, while
6205 * we just avoid overriding existing entries.
6207 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6208 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6210 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6217 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6218 for (n
= 0; n
<= 65535; n
++)
6219 glyph_to_char
[n
] = (USHORT
)n
;
6222 tt_kern_table
= buf
;
6223 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6224 TRACE("version %u, nTables %u\n",
6225 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6227 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6229 for (i
= 0; i
< nTables
; i
++)
6231 struct TT_kern_subtable tt_kern_subtable_copy
;
6233 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6234 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6235 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6237 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6238 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6239 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6241 /* According to the TrueType specification this is the only format
6242 * that will be properly interpreted by Windows and OS/2
6244 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6246 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6248 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6249 glyph_to_char
, NULL
, 0);
6250 font
->total_kern_pairs
+= new_chunk
;
6252 if (!font
->kern_pairs
)
6253 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6254 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6256 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6257 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6259 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6260 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6263 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6265 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6268 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6269 HeapFree(GetProcessHeap(), 0, buf
);
6271 if (cPairs
&& kern_pair
)
6273 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6274 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6275 LeaveCriticalSection( &freetype_cs
);
6278 LeaveCriticalSection( &freetype_cs
);
6279 return font
->total_kern_pairs
;
6282 #else /* HAVE_FREETYPE */
6284 /*************************************************************************/
6286 BOOL
WineEngInit(void)
6290 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6294 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6299 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6304 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6305 LPWORD pgi
, DWORD flags
)
6310 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6311 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6314 ERR("called but we don't have FreeType\n");
6318 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6320 ERR("called but we don't have FreeType\n");
6324 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6325 OUTLINETEXTMETRICW
*potm
)
6327 ERR("called but we don't have FreeType\n");
6331 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6334 ERR("called but we don't have FreeType\n");
6338 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6341 ERR("called but we don't have FreeType\n");
6345 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6348 ERR("called but we don't have FreeType\n");
6352 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6353 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6355 ERR("called but we don't have FreeType\n");
6359 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6360 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6362 ERR("called but we don't have FreeType\n");
6366 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6369 ERR("called but we don't have FreeType\n");
6373 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6375 ERR("called but we don't have FreeType\n");
6379 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6385 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6391 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6397 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6400 return DEFAULT_CHARSET
;
6403 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6408 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6410 FIXME("(%p, %p): stub\n", font
, glyphset
);
6414 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6419 /*************************************************************************
6420 * GetRasterizerCaps (GDI32.@)
6422 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6424 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6426 lprs
->nLanguageID
= 0;
6430 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6432 ERR("called but we don't have FreeType\n");
6436 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6438 ERR("called but we don't have FreeType\n");
6442 #endif /* HAVE_FREETYPE */