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
&& !strcmpiW(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(!strcmpiW(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(!strcmpiW(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 memset(&fs
, 0, sizeof(fs
));
1655 psub
= get_font_subst(&font_subst_list
, value
, -1);
1656 /* Don't store fonts that are only substitutes for other fonts */
1659 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1662 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1663 font_link
->font_name
= strdupW(value
);
1664 list_init(&font_link
->links
);
1665 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1668 CHILD_FONT
*child_font
;
1670 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1672 next
= entry
+ strlenW(entry
) + 1;
1674 face_name
= strchrW(entry
, ',');
1678 while(isspaceW(*face_name
))
1681 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1683 face_name
= psub
->to
.name
;
1685 face
= find_face_from_filename(entry
, face_name
);
1688 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1692 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1693 child_font
->face
= face
;
1694 child_font
->font
= NULL
;
1695 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1696 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1697 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1698 list_add_tail(&font_link
->links
, &child_font
->entry
);
1700 family
= find_family_from_name(font_link
->font_name
);
1703 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1705 face
->fs_links
= fs
;
1708 list_add_tail(&system_links
, &font_link
->entry
);
1709 val_len
= max_val
+ 1;
1710 data_len
= max_data
;
1713 HeapFree(GetProcessHeap(), 0, value
);
1714 HeapFree(GetProcessHeap(), 0, data
);
1718 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1721 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1722 system_font_link
->font_name
= strdupW(System
);
1723 list_init(&system_font_link
->links
);
1725 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1728 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1729 child_font
->face
= face
;
1730 child_font
->font
= NULL
;
1731 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1732 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1734 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1736 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1738 CHILD_FONT
*font_link_entry
;
1739 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1741 CHILD_FONT
*new_child
;
1742 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1743 new_child
->face
= font_link_entry
->face
;
1744 new_child
->font
= NULL
;
1745 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1750 list_add_tail(&system_links
, &system_font_link
->entry
);
1754 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1757 struct dirent
*dent
;
1758 char path
[MAX_PATH
];
1760 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1762 dir
= opendir(dirname
);
1764 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1767 while((dent
= readdir(dir
)) != NULL
) {
1768 struct stat statbuf
;
1770 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1773 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1775 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1777 if(stat(path
, &statbuf
) == -1)
1779 WARN("Can't stat %s\n", debugstr_a(path
));
1782 if(S_ISDIR(statbuf
.st_mode
))
1783 ReadFontDir(path
, external_fonts
);
1785 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1791 static void load_fontconfig_fonts(void)
1793 #ifdef SONAME_LIBFONTCONFIG
1794 void *fc_handle
= NULL
;
1803 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1805 TRACE("Wine cannot find the fontconfig library (%s).\n",
1806 SONAME_LIBFONTCONFIG
);
1809 #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;}
1810 LOAD_FUNCPTR(FcConfigGetCurrent
);
1811 LOAD_FUNCPTR(FcFontList
);
1812 LOAD_FUNCPTR(FcFontSetDestroy
);
1813 LOAD_FUNCPTR(FcInit
);
1814 LOAD_FUNCPTR(FcObjectSetAdd
);
1815 LOAD_FUNCPTR(FcObjectSetCreate
);
1816 LOAD_FUNCPTR(FcObjectSetDestroy
);
1817 LOAD_FUNCPTR(FcPatternCreate
);
1818 LOAD_FUNCPTR(FcPatternDestroy
);
1819 LOAD_FUNCPTR(FcPatternGetBool
);
1820 LOAD_FUNCPTR(FcPatternGetString
);
1823 if(!pFcInit()) return;
1825 config
= pFcConfigGetCurrent();
1826 pat
= pFcPatternCreate();
1827 os
= pFcObjectSetCreate();
1828 pFcObjectSetAdd(os
, FC_FILE
);
1829 pFcObjectSetAdd(os
, FC_SCALABLE
);
1830 fontset
= pFcFontList(config
, pat
, os
);
1831 if(!fontset
) return;
1832 for(i
= 0; i
< fontset
->nfont
; i
++) {
1835 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1837 TRACE("fontconfig: %s\n", file
);
1839 /* We're just interested in OT/TT fonts for now, so this hack just
1840 picks up the scalable fonts without extensions .pf[ab] to save time
1841 loading every other font */
1843 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1845 TRACE("not scalable\n");
1849 len
= strlen( file
);
1850 if(len
< 4) continue;
1851 ext
= &file
[ len
- 3 ];
1852 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1853 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1855 pFcFontSetDestroy(fontset
);
1856 pFcObjectSetDestroy(os
);
1857 pFcPatternDestroy(pat
);
1863 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1866 const char *data_dir
= wine_get_data_dir();
1868 if (!data_dir
) data_dir
= wine_get_build_dir();
1875 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1877 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1879 strcpy(unix_name
, data_dir
);
1880 strcat(unix_name
, "/fonts/");
1882 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1884 EnterCriticalSection( &freetype_cs
);
1885 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1886 LeaveCriticalSection( &freetype_cs
);
1887 HeapFree(GetProcessHeap(), 0, unix_name
);
1892 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1894 static const WCHAR slashW
[] = {'\\','\0'};
1896 WCHAR windowsdir
[MAX_PATH
];
1899 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1900 strcatW(windowsdir
, fontsW
);
1901 strcatW(windowsdir
, slashW
);
1902 strcatW(windowsdir
, file
);
1903 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1904 EnterCriticalSection( &freetype_cs
);
1905 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1906 LeaveCriticalSection( &freetype_cs
);
1907 HeapFree(GetProcessHeap(), 0, unixname
);
1912 static void load_system_fonts(void)
1915 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1916 const WCHAR
* const *value
;
1918 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1921 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1922 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1923 strcatW(windowsdir
, fontsW
);
1924 for(value
= SystemFontValues
; *value
; value
++) {
1925 dlen
= sizeof(data
);
1926 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1930 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1931 if((unixname
= wine_get_unix_file_name(pathW
))) {
1932 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1933 HeapFree(GetProcessHeap(), 0, unixname
);
1936 load_font_from_data_dir(data
);
1943 /*************************************************************
1945 * This adds registry entries for any externally loaded fonts
1946 * (fonts from fontconfig or FontDirs). It also deletes entries
1947 * of no longer existing fonts.
1950 static void update_reg_entries(void)
1952 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1957 struct list
*family_elem_ptr
, *face_elem_ptr
;
1959 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1960 static const WCHAR spaceW
[] = {' ', '\0'};
1963 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1964 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1965 ERR("Can't create Windows font reg key\n");
1969 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1970 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1971 ERR("Can't create Windows font reg key\n");
1975 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1976 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1977 ERR("Can't create external font reg key\n");
1981 /* enumerate the fonts and add external ones to the two keys */
1983 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1984 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1985 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1986 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1987 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1988 if(!face
->external
) continue;
1990 if (!(face
->ntmFlags
& NTM_REGULAR
))
1991 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1992 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1993 strcpyW(valueW
, family
->FamilyName
);
1994 if(len
!= len_fam
) {
1995 strcatW(valueW
, spaceW
);
1996 strcatW(valueW
, face
->StyleName
);
1998 strcatW(valueW
, TrueType
);
2000 file
= wine_get_dos_file_name(face
->file
);
2002 len
= strlenW(file
) + 1;
2005 if((path
= strrchr(face
->file
, '/')) == NULL
)
2009 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2011 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2012 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2014 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2015 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2016 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2018 HeapFree(GetProcessHeap(), 0, file
);
2019 HeapFree(GetProcessHeap(), 0, valueW
);
2023 if(external_key
) RegCloseKey(external_key
);
2024 if(win9x_key
) RegCloseKey(win9x_key
);
2025 if(winnt_key
) RegCloseKey(winnt_key
);
2029 static void delete_external_font_keys(void)
2031 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2032 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2036 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2037 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2038 ERR("Can't create Windows font reg key\n");
2042 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2043 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2044 ERR("Can't create Windows font reg key\n");
2048 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2049 ERR("Can't create external font reg key\n");
2053 /* Delete all external fonts added last time */
2055 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2056 &valuelen
, &datalen
, NULL
, NULL
);
2057 valuelen
++; /* returned value doesn't include room for '\0' */
2058 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2059 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2061 dlen
= datalen
* sizeof(WCHAR
);
2064 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2065 &dlen
) == ERROR_SUCCESS
) {
2067 RegDeleteValueW(winnt_key
, valueW
);
2068 RegDeleteValueW(win9x_key
, valueW
);
2069 /* reset dlen and vlen */
2073 HeapFree(GetProcessHeap(), 0, data
);
2074 HeapFree(GetProcessHeap(), 0, valueW
);
2076 /* Delete the old external fonts key */
2077 RegCloseKey(external_key
);
2078 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2081 if(win9x_key
) RegCloseKey(win9x_key
);
2082 if(winnt_key
) RegCloseKey(winnt_key
);
2085 /*************************************************************
2086 * WineEngAddFontResourceEx
2089 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2095 if (ft_handle
) /* do it only if we have freetype up and running */
2100 FIXME("Ignoring flags %x\n", flags
);
2102 if((unixname
= wine_get_unix_file_name(file
)))
2104 EnterCriticalSection( &freetype_cs
);
2105 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2106 LeaveCriticalSection( &freetype_cs
);
2107 HeapFree(GetProcessHeap(), 0, unixname
);
2109 if (!ret
&& !strchrW(file
, '\\')) {
2110 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2111 ret
= load_font_from_winfonts_dir(file
);
2113 /* Try in datadir/fonts (or builddir/fonts),
2114 * needed for Magic the Gathering Online
2116 ret
= load_font_from_data_dir(file
);
2123 /*************************************************************
2124 * WineEngAddFontMemResourceEx
2127 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2131 if (ft_handle
) /* do it only if we have freetype up and running */
2133 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2135 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2136 memcpy(pFontCopy
, pbFont
, cbFont
);
2138 EnterCriticalSection( &freetype_cs
);
2139 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2140 LeaveCriticalSection( &freetype_cs
);
2144 TRACE("AddFontToList failed\n");
2145 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2148 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2149 * For now return something unique but quite random
2151 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2152 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2159 /*************************************************************
2160 * WineEngRemoveFontResourceEx
2163 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2170 static const struct nls_update_font_list
2172 UINT ansi_cp
, oem_cp
;
2173 const char *oem
, *fixed
, *system
;
2174 const char *courier
, *serif
, *small
, *sserif
;
2175 /* these are for font substitutes */
2176 const char *shelldlg
, *tmsrmn
;
2177 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2181 const char *from
, *to
;
2182 } arial_0
, courier_new_0
, times_new_roman_0
;
2183 } nls_update_font_list
[] =
2185 /* Latin 1 (United States) */
2186 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2187 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2188 "Tahoma","Times New Roman",
2189 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2192 /* Latin 1 (Multilingual) */
2193 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2194 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2195 "Tahoma","Times New Roman", /* FIXME unverified */
2196 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2199 /* Eastern Europe */
2200 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2201 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2202 "Tahoma","Times New Roman", /* FIXME unverified */
2203 "Fixedsys,238", "System,238",
2204 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2205 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2206 { "Arial CE,0", "Arial,238" },
2207 { "Courier New CE,0", "Courier New,238" },
2208 { "Times New Roman CE,0", "Times New Roman,238" }
2211 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2212 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2213 "Tahoma","Times New Roman", /* FIXME unverified */
2214 "Fixedsys,204", "System,204",
2215 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2216 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2217 { "Arial Cyr,0", "Arial,204" },
2218 { "Courier New Cyr,0", "Courier New,204" },
2219 { "Times New Roman Cyr,0", "Times New Roman,204" }
2222 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2223 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2224 "Tahoma","Times New Roman", /* FIXME unverified */
2225 "Fixedsys,161", "System,161",
2226 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2227 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2228 { "Arial Greek,0", "Arial,161" },
2229 { "Courier New Greek,0", "Courier New,161" },
2230 { "Times New Roman Greek,0", "Times New Roman,161" }
2233 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2234 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2235 "Tahoma","Times New Roman", /* FIXME unverified */
2236 "Fixedsys,162", "System,162",
2237 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2238 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2239 { "Arial Tur,0", "Arial,162" },
2240 { "Courier New Tur,0", "Courier New,162" },
2241 { "Times New Roman Tur,0", "Times New Roman,162" }
2244 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2245 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2246 "Tahoma","Times New Roman", /* FIXME unverified */
2247 "Fixedsys,177", "System,177",
2248 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2249 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2253 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2254 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2255 "Tahoma","Times New Roman", /* FIXME unverified */
2256 "Fixedsys,178", "System,178",
2257 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2258 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2262 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2263 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2264 "Tahoma","Times New Roman", /* FIXME unverified */
2265 "Fixedsys,186", "System,186",
2266 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2267 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2268 { "Arial Baltic,0", "Arial,186" },
2269 { "Courier New Baltic,0", "Courier New,186" },
2270 { "Times New Roman Baltic,0", "Times New Roman,186" }
2273 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2274 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2275 "Tahoma","Times New Roman", /* FIXME unverified */
2276 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2280 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2281 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2282 "Tahoma","Times New Roman", /* FIXME unverified */
2283 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2287 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2288 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2289 "MS UI Gothic","MS Serif",
2290 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2293 /* Chinese Simplified */
2294 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2295 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2296 "SimSun", "NSimSun",
2297 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2301 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2302 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2304 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2307 /* Chinese Traditional */
2308 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2309 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2310 "PMingLiU", "MingLiU",
2311 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2316 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2318 return ( ansi_cp
== 932 /* CP932 for Japanese */
2319 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2320 || ansi_cp
== 949 /* CP949 for Korean */
2321 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2324 static inline HKEY
create_fonts_NT_registry_key(void)
2328 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2329 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2333 static inline HKEY
create_fonts_9x_registry_key(void)
2337 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2338 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2342 static inline HKEY
create_config_fonts_registry_key(void)
2346 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2347 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2351 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2353 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2354 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2355 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2356 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2359 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2362 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2364 RegDeleteValueA(hkey
, name
);
2367 static void update_font_info(void)
2369 char buf
[40], cpbuf
[40];
2372 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2375 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2378 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2379 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2380 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2381 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2382 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2384 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2385 if (is_dbcs_ansi_cp(ansi_cp
))
2386 use_default_fallback
= TRUE
;
2389 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2391 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2396 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2398 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2400 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2403 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2407 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2408 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2410 hkey
= create_config_fonts_registry_key();
2411 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2412 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2413 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2416 hkey
= create_fonts_NT_registry_key();
2417 add_font_list(hkey
, &nls_update_font_list
[i
]);
2420 hkey
= create_fonts_9x_registry_key();
2421 add_font_list(hkey
, &nls_update_font_list
[i
]);
2424 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2426 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2427 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2428 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2429 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2431 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2432 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2433 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2434 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2435 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2436 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2437 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2438 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2440 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2441 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2442 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2450 /* Delete the FontSubstitutes from other locales */
2451 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2453 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2454 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2455 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2461 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2465 static BOOL
init_freetype(void)
2467 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2470 "Wine cannot find the FreeType font library. To enable Wine to\n"
2471 "use TrueType fonts please install a version of FreeType greater than\n"
2472 "or equal to 2.0.5.\n"
2473 "http://www.freetype.org\n");
2477 #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;}
2479 LOAD_FUNCPTR(FT_Vector_Unit
)
2480 LOAD_FUNCPTR(FT_Done_Face
)
2481 LOAD_FUNCPTR(FT_Get_Char_Index
)
2482 LOAD_FUNCPTR(FT_Get_Module
)
2483 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2484 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2485 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2486 LOAD_FUNCPTR(FT_Init_FreeType
)
2487 LOAD_FUNCPTR(FT_Load_Glyph
)
2488 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2489 #ifndef FT_MULFIX_INLINED
2490 LOAD_FUNCPTR(FT_MulFix
)
2492 LOAD_FUNCPTR(FT_New_Face
)
2493 LOAD_FUNCPTR(FT_New_Memory_Face
)
2494 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2495 LOAD_FUNCPTR(FT_Outline_Transform
)
2496 LOAD_FUNCPTR(FT_Outline_Translate
)
2497 LOAD_FUNCPTR(FT_Select_Charmap
)
2498 LOAD_FUNCPTR(FT_Set_Charmap
)
2499 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2500 LOAD_FUNCPTR(FT_Vector_Transform
)
2501 LOAD_FUNCPTR(FT_Render_Glyph
)
2504 /* Don't warn if these ones are missing */
2505 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2506 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2507 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2508 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2509 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2510 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2511 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2513 #ifdef HAVE_FREETYPE_FTWINFNT_H
2514 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2516 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2517 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2518 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2519 <= 2.0.3 has FT_Sqrt64 */
2523 if(pFT_Init_FreeType(&library
) != 0) {
2524 ERR("Can't init FreeType library\n");
2525 wine_dlclose(ft_handle
, NULL
, 0);
2529 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2530 if (pFT_Library_Version
)
2531 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2533 if (FT_Version
.major
<=0)
2539 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2540 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2541 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2542 ((FT_Version
.patch
) & 0x0000ff);
2548 "Wine cannot find certain functions that it needs inside the FreeType\n"
2549 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2550 "FreeType to at least version 2.0.5.\n"
2551 "http://www.freetype.org\n");
2552 wine_dlclose(ft_handle
, NULL
, 0);
2557 /*************************************************************
2560 * Initialize FreeType library and create a list of available faces
2562 BOOL
WineEngInit(void)
2564 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2565 static const WCHAR pathW
[] = {'P','a','t','h',0};
2567 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2568 WCHAR windowsdir
[MAX_PATH
];
2571 const char *data_dir
;
2575 /* update locale dependent font info in registry */
2578 if(!init_freetype()) return FALSE
;
2580 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2581 ERR("Failed to create font mutex\n");
2584 WaitForSingleObject(font_mutex
, INFINITE
);
2586 delete_external_font_keys();
2588 /* load the system bitmap fonts */
2589 load_system_fonts();
2591 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2592 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2593 strcatW(windowsdir
, fontsW
);
2594 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2596 ReadFontDir(unixname
, FALSE
);
2597 HeapFree(GetProcessHeap(), 0, unixname
);
2600 /* load the system truetype fonts */
2601 data_dir
= wine_get_data_dir();
2602 if (!data_dir
) data_dir
= wine_get_build_dir();
2603 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2604 strcpy(unixname
, data_dir
);
2605 strcat(unixname
, "/fonts/");
2606 ReadFontDir(unixname
, TRUE
);
2607 HeapFree(GetProcessHeap(), 0, unixname
);
2610 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2611 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2612 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2614 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2615 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2616 &hkey
) == ERROR_SUCCESS
) {
2617 LPWSTR data
, valueW
;
2618 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2619 &valuelen
, &datalen
, NULL
, NULL
);
2621 valuelen
++; /* returned value doesn't include room for '\0' */
2622 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2623 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2626 dlen
= datalen
* sizeof(WCHAR
);
2628 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
2629 &dlen
) == ERROR_SUCCESS
) {
2630 if(data
[0] && (data
[1] == ':'))
2632 if((unixname
= wine_get_unix_file_name(data
)))
2634 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2635 HeapFree(GetProcessHeap(), 0, unixname
);
2638 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
2640 WCHAR pathW
[MAX_PATH
];
2641 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2644 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2645 if((unixname
= wine_get_unix_file_name(pathW
)))
2647 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2648 HeapFree(GetProcessHeap(), 0, unixname
);
2651 load_font_from_data_dir(data
);
2653 /* reset dlen and vlen */
2658 HeapFree(GetProcessHeap(), 0, data
);
2659 HeapFree(GetProcessHeap(), 0, valueW
);
2663 load_fontconfig_fonts();
2665 /* then look in any directories that we've specified in the config file */
2666 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2667 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2673 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2675 len
+= sizeof(WCHAR
);
2676 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2677 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2679 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2680 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2681 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2682 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2686 LPSTR next
= strchr( ptr
, ':' );
2687 if (next
) *next
++ = 0;
2688 ReadFontDir( ptr
, TRUE
);
2691 HeapFree( GetProcessHeap(), 0, valueA
);
2693 HeapFree( GetProcessHeap(), 0, valueW
);
2702 update_reg_entries();
2704 init_system_links();
2706 ReleaseMutex(font_mutex
);
2711 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2714 TT_HoriHeader
*pHori
;
2718 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2719 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2721 if(height
== 0) height
= 16;
2723 /* Calc. height of EM square:
2725 * For +ve lfHeight we have
2726 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2727 * Re-arranging gives:
2728 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2730 * For -ve lfHeight we have
2732 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2733 * with il = winAscent + winDescent - units_per_em]
2738 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2739 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2740 pHori
->Ascender
- pHori
->Descender
);
2742 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2743 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2751 static struct font_mapping
*map_font_file( const char *name
)
2753 struct font_mapping
*mapping
;
2757 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2758 if (fstat( fd
, &st
) == -1) goto error
;
2760 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2762 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2764 mapping
->refcount
++;
2769 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2772 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2775 if (mapping
->data
== MAP_FAILED
)
2777 HeapFree( GetProcessHeap(), 0, mapping
);
2780 mapping
->refcount
= 1;
2781 mapping
->dev
= st
.st_dev
;
2782 mapping
->ino
= st
.st_ino
;
2783 mapping
->size
= st
.st_size
;
2784 list_add_tail( &mappings_list
, &mapping
->entry
);
2792 static void unmap_font_file( struct font_mapping
*mapping
)
2794 if (!--mapping
->refcount
)
2796 list_remove( &mapping
->entry
);
2797 munmap( mapping
->data
, mapping
->size
);
2798 HeapFree( GetProcessHeap(), 0, mapping
);
2802 static LONG
load_VDMX(GdiFont
*, LONG
);
2804 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2811 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2815 if (!(font
->mapping
= map_font_file( face
->file
)))
2817 WARN("failed to map %s\n", debugstr_a(face
->file
));
2820 data_ptr
= font
->mapping
->data
;
2821 data_size
= font
->mapping
->size
;
2825 data_ptr
= face
->font_data_ptr
;
2826 data_size
= face
->font_data_size
;
2829 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2831 ERR("FT_New_Face rets %d\n", err
);
2835 /* set it here, as load_VDMX needs it */
2836 font
->ft_face
= ft_face
;
2838 if(FT_IS_SCALABLE(ft_face
)) {
2839 /* load the VDMX table if we have one */
2840 font
->ppem
= load_VDMX(font
, height
);
2842 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2843 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
2845 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2846 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2848 font
->ppem
= height
;
2849 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2850 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2856 static int get_nearest_charset(Face
*face
, int *cp
)
2858 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2859 a single face with the requested charset. The idea is to check if
2860 the selected font supports the current ANSI codepage, if it does
2861 return the corresponding charset, else return the first charset */
2864 int acp
= GetACP(), i
;
2868 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2869 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2870 return csi
.ciCharset
;
2872 for(i
= 0; i
< 32; i
++) {
2874 if(face
->fs
.fsCsb
[0] & fs0
) {
2875 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2877 return csi
.ciCharset
;
2880 FIXME("TCI failing on %x\n", fs0
);
2884 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2885 face
->fs
.fsCsb
[0], face
->file
);
2887 return DEFAULT_CHARSET
;
2890 static GdiFont
*alloc_font(void)
2892 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2894 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2895 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2897 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2898 ret
->total_kern_pairs
= (DWORD
)-1;
2899 ret
->kern_pairs
= NULL
;
2900 list_init(&ret
->hfontlist
);
2901 list_init(&ret
->child_fonts
);
2905 static void free_font(GdiFont
*font
)
2907 struct list
*cursor
, *cursor2
;
2910 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2912 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2913 struct list
*first_hfont
;
2914 HFONTLIST
*hfontlist
;
2915 list_remove(cursor
);
2918 first_hfont
= list_head(&child
->font
->hfontlist
);
2919 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2920 DeleteObject(hfontlist
->hfont
);
2921 HeapFree(GetProcessHeap(), 0, hfontlist
);
2922 free_font(child
->font
);
2924 HeapFree(GetProcessHeap(), 0, child
);
2927 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2928 if (font
->mapping
) unmap_font_file( font
->mapping
);
2929 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2930 HeapFree(GetProcessHeap(), 0, font
->potm
);
2931 HeapFree(GetProcessHeap(), 0, font
->name
);
2932 for (i
= 0; i
< font
->gmsize
; i
++)
2933 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2934 HeapFree(GetProcessHeap(), 0, font
->gm
);
2935 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
2936 HeapFree(GetProcessHeap(), 0, font
);
2940 /*************************************************************
2943 * load the vdmx entry for the specified height
2946 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2947 ( ( (FT_ULong)_x4 << 24 ) | \
2948 ( (FT_ULong)_x3 << 16 ) | \
2949 ( (FT_ULong)_x2 << 8 ) | \
2952 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2967 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2971 BYTE devXRatio
, devYRatio
;
2972 USHORT numRecs
, numRatios
;
2973 DWORD result
, offset
= -1;
2977 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2979 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2982 /* FIXME: need the real device aspect ratio */
2986 numRecs
= GET_BE_WORD(hdr
[1]);
2987 numRatios
= GET_BE_WORD(hdr
[2]);
2989 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2990 for(i
= 0; i
< numRatios
; i
++) {
2993 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2994 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2997 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2999 if((ratio
.xRatio
== 0 &&
3000 ratio
.yStartRatio
== 0 &&
3001 ratio
.yEndRatio
== 0) ||
3002 (devXRatio
== ratio
.xRatio
&&
3003 devYRatio
>= ratio
.yStartRatio
&&
3004 devYRatio
<= ratio
.yEndRatio
))
3006 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3007 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3008 offset
= GET_BE_WORD(tmp
);
3014 FIXME("No suitable ratio found\n");
3018 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3020 BYTE startsz
, endsz
;
3023 recs
= GET_BE_WORD(group
.recs
);
3024 startsz
= group
.startsz
;
3025 endsz
= group
.endsz
;
3027 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3029 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3030 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3031 if(result
== GDI_ERROR
) {
3032 FIXME("Failed to retrieve vTable\n");
3037 for(i
= 0; i
< recs
; i
++) {
3038 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3039 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3040 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3042 if(yMax
+ -yMin
== height
) {
3045 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3048 if(yMax
+ -yMin
> height
) {
3051 goto end
; /* failed */
3053 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3054 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3055 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3056 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3062 TRACE("ppem not found for height %d\n", height
);
3066 if(ppem
< startsz
|| ppem
> endsz
)
3069 for(i
= 0; i
< recs
; i
++) {
3071 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
3073 if(yPelHeight
> ppem
)
3076 if(yPelHeight
== ppem
) {
3077 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3078 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3079 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
3085 HeapFree(GetProcessHeap(), 0, vTable
);
3091 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3093 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3094 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3095 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3096 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3097 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3100 static void calc_hash(FONT_DESC
*pfd
)
3102 DWORD hash
= 0, *ptr
, two_chars
;
3106 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3108 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3110 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3112 pwc
= (WCHAR
*)&two_chars
;
3114 *pwc
= toupperW(*pwc
);
3116 *pwc
= toupperW(*pwc
);
3120 hash
^= !pfd
->can_use_bitmap
;
3125 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3130 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3134 fd
.can_use_bitmap
= can_use_bitmap
;
3137 /* try the child list */
3138 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3139 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3140 if(!fontcmp(ret
, &fd
)) {
3141 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3142 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3143 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3144 if(hflist
->hfont
== hfont
)
3150 /* try the in-use list */
3151 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3152 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3153 if(!fontcmp(ret
, &fd
)) {
3154 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3155 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3156 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3157 if(hflist
->hfont
== hfont
)
3160 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3161 hflist
->hfont
= hfont
;
3162 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3167 /* then the unused list */
3168 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3169 while(font_elem_ptr
) {
3170 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3171 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3172 if(!fontcmp(ret
, &fd
)) {
3173 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3174 assert(list_empty(&ret
->hfontlist
));
3175 TRACE("Found %p in unused list\n", ret
);
3176 list_remove(&ret
->entry
);
3177 list_add_head(&gdi_font_list
, &ret
->entry
);
3178 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3179 hflist
->hfont
= hfont
;
3180 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3187 static void add_to_cache(GdiFont
*font
)
3189 static DWORD cache_num
= 1;
3191 font
->cache_num
= cache_num
++;
3192 list_add_head(&gdi_font_list
, &font
->entry
);
3195 /*************************************************************
3196 * create_child_font_list
3198 static BOOL
create_child_font_list(GdiFont
*font
)
3201 SYSTEM_LINKS
*font_link
;
3202 CHILD_FONT
*font_link_entry
, *new_child
;
3206 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3207 font_name
= psub
? psub
->to
.name
: font
->name
;
3208 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3210 if(!strcmpiW(font_link
->font_name
, font_name
))
3212 TRACE("found entry in system list\n");
3213 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3215 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3216 new_child
->face
= font_link_entry
->face
;
3217 new_child
->font
= NULL
;
3218 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3219 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3226 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3227 * Sans Serif. This is how asian windows get default fallbacks for fonts
3229 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3230 font
->charset
!= OEM_CHARSET
&&
3231 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3232 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3234 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3236 TRACE("found entry in default fallback list\n");
3237 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3239 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3240 new_child
->face
= font_link_entry
->face
;
3241 new_child
->font
= NULL
;
3242 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3243 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3253 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3255 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3257 if (pFT_Set_Charmap
)
3260 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3262 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3264 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3266 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3268 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3269 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3271 switch (ft_face
->charmaps
[i
]->platform_id
)
3274 cmap_def
= ft_face
->charmaps
[i
];
3276 case 0: /* Apple Unicode */
3277 cmap0
= ft_face
->charmaps
[i
];
3279 case 1: /* Macintosh */
3280 cmap1
= ft_face
->charmaps
[i
];
3283 cmap2
= ft_face
->charmaps
[i
];
3285 case 3: /* Microsoft */
3286 cmap3
= ft_face
->charmaps
[i
];
3291 if (cmap3
) /* prefer Microsoft cmap table */
3292 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3294 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3296 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3298 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3300 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3302 return ft_err
== FT_Err_Ok
;
3305 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3308 /*************************************************************
3309 * WineEngCreateFontInstance
3312 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3315 Face
*face
, *best
, *best_bitmap
;
3316 Family
*family
, *last_resort_family
;
3317 struct list
*family_elem_ptr
, *face_elem_ptr
;
3318 INT height
, width
= 0;
3319 unsigned int score
= 0, new_score
;
3320 signed int diff
= 0, newdiff
;
3321 BOOL bd
, it
, can_use_bitmap
;
3326 FontSubst
*psub
= NULL
;
3328 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3329 lf
.lfWidth
= abs(lf
.lfWidth
);
3331 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3333 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3334 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3335 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3338 if(dc
->GraphicsMode
== GM_ADVANCED
)
3339 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3342 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3343 font scaling abilities. */
3344 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3345 dcmat
.eM21
= dcmat
.eM12
= 0;
3348 /* Try to avoid not necessary glyph transformations */
3349 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3351 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3352 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3353 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3356 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3357 dcmat
.eM21
, dcmat
.eM22
);
3360 EnterCriticalSection( &freetype_cs
);
3362 /* check the cache first */
3363 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3364 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3365 LeaveCriticalSection( &freetype_cs
);
3369 TRACE("not in cache\n");
3370 if(list_empty(&font_list
)) /* No fonts installed */
3372 TRACE("No fonts installed\n");
3373 LeaveCriticalSection( &freetype_cs
);
3376 if(!have_installed_roman_font
)
3378 TRACE("No roman font installed\n");
3379 LeaveCriticalSection( &freetype_cs
);
3385 ret
->font_desc
.matrix
= dcmat
;
3386 ret
->font_desc
.lf
= lf
;
3387 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3388 calc_hash(&ret
->font_desc
);
3389 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3390 hflist
->hfont
= hfont
;
3391 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3393 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3394 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3395 original value lfCharSet. Note this is a special case for
3396 Symbol and doesn't happen at least for "Wingdings*" */
3398 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3399 lf
.lfCharSet
= SYMBOL_CHARSET
;
3401 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3402 switch(lf
.lfCharSet
) {
3403 case DEFAULT_CHARSET
:
3404 csi
.fs
.fsCsb
[0] = 0;
3407 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3408 csi
.fs
.fsCsb
[0] = 0;
3414 if(lf
.lfFaceName
[0] != '\0') {
3415 SYSTEM_LINKS
*font_link
;
3416 CHILD_FONT
*font_link_entry
;
3417 LPWSTR FaceName
= lf
.lfFaceName
;
3420 * Check for a leading '@' this signals that the font is being
3421 * requested in tategaki mode (vertical writing substitution) but
3422 * does not affect the fontface that is to be selected.
3424 if (lf
.lfFaceName
[0]=='@')
3425 FaceName
= &lf
.lfFaceName
[1];
3427 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3430 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3431 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3432 if (psub
->to
.charset
!= -1)
3433 lf
.lfCharSet
= psub
->to
.charset
;
3436 /* We want a match on name and charset or just name if
3437 charset was DEFAULT_CHARSET. If the latter then
3438 we fixup the returned charset later in get_nearest_charset
3439 where we'll either use the charset of the current ansi codepage
3440 or if that's unavailable the first charset that the font supports.
3442 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3443 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3444 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3445 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3447 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3448 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3449 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3450 if(face
->scalable
|| can_use_bitmap
)
3457 * Try check the SystemLink list first for a replacement font.
3458 * We may find good replacements there.
3460 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3462 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3463 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3465 TRACE("found entry in system list\n");
3466 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3468 face
= font_link_entry
->face
;
3469 family
= face
->family
;
3470 if(csi
.fs
.fsCsb
[0] &
3471 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3473 if(face
->scalable
|| can_use_bitmap
)
3481 psub
= NULL
; /* substitution is no more relevant */
3483 /* If requested charset was DEFAULT_CHARSET then try using charset
3484 corresponding to the current ansi codepage */
3485 if (!csi
.fs
.fsCsb
[0])
3488 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3489 FIXME("TCI failed on codepage %d\n", acp
);
3490 csi
.fs
.fsCsb
[0] = 0;
3492 lf
.lfCharSet
= csi
.ciCharset
;
3495 /* Face families are in the top 4 bits of lfPitchAndFamily,
3496 so mask with 0xF0 before testing */
3498 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3499 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3500 strcpyW(lf
.lfFaceName
, defFixed
);
3501 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3502 strcpyW(lf
.lfFaceName
, defSerif
);
3503 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3504 strcpyW(lf
.lfFaceName
, defSans
);
3506 strcpyW(lf
.lfFaceName
, defSans
);
3507 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3508 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3509 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3510 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3511 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3512 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3513 if(face
->scalable
|| can_use_bitmap
)
3519 last_resort_family
= NULL
;
3520 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3521 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3522 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3523 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3524 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3527 if(can_use_bitmap
&& !last_resort_family
)
3528 last_resort_family
= family
;
3533 if(last_resort_family
) {
3534 family
= last_resort_family
;
3535 csi
.fs
.fsCsb
[0] = 0;
3539 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3540 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3541 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3542 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3543 if(face
->scalable
) {
3544 csi
.fs
.fsCsb
[0] = 0;
3545 WARN("just using first face for now\n");
3548 if(can_use_bitmap
&& !last_resort_family
)
3549 last_resort_family
= family
;
3552 if(!last_resort_family
) {
3553 FIXME("can't find a single appropriate font - bailing\n");
3555 LeaveCriticalSection( &freetype_cs
);
3559 WARN("could only find a bitmap font - this will probably look awful!\n");
3560 family
= last_resort_family
;
3561 csi
.fs
.fsCsb
[0] = 0;
3564 it
= lf
.lfItalic
? 1 : 0;
3565 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3567 height
= lf
.lfHeight
;
3569 face
= best
= best_bitmap
= NULL
;
3570 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3572 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3576 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3577 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3578 new_score
= (italic
^ it
) + (bold
^ bd
);
3579 if(!best
|| new_score
<= score
)
3581 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3582 italic
, bold
, it
, bd
);
3585 if(best
->scalable
&& score
== 0) break;
3589 newdiff
= height
- (signed int)(best
->size
.height
);
3591 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3592 if(!best_bitmap
|| new_score
< score
||
3593 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3595 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3598 if(score
== 0 && diff
== 0) break;
3605 face
= best
->scalable
? best
: best_bitmap
;
3606 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3607 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3611 if(csi
.fs
.fsCsb
[0]) {
3612 ret
->charset
= lf
.lfCharSet
;
3613 ret
->codepage
= csi
.ciACP
;
3616 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3618 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3619 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3621 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3623 if(!face
->scalable
) {
3624 /* Windows uses integer scaling factors for bitmap fonts */
3625 INT scale
, scaled_height
;
3627 /* FIXME: rotation of bitmap fonts is ignored */
3628 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3630 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3631 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3633 if (height
!= 0) height
= diff
;
3634 height
+= face
->size
.height
;
3636 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3637 scaled_height
= scale
* face
->size
.height
;
3638 /* Only jump to the next height if the difference <= 25% original height */
3639 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3640 /* The jump between unscaled and doubled is delayed by 1 */
3641 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3642 ret
->scale_y
= scale
;
3644 width
= face
->size
.x_ppem
>> 6;
3645 height
= face
->size
.y_ppem
>> 6;
3649 TRACE("font scale y: %f\n", ret
->scale_y
);
3651 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3656 LeaveCriticalSection( &freetype_cs
);
3660 ret
->ntmFlags
= face
->ntmFlags
;
3662 if (ret
->charset
== SYMBOL_CHARSET
&&
3663 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3666 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3670 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3673 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3674 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3675 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3676 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3677 create_child_font_list(ret
);
3679 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3681 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3682 if (length
!= GDI_ERROR
)
3684 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3685 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3686 TRACE("Loaded GSUB table of %i bytes\n",length
);
3690 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3693 LeaveCriticalSection( &freetype_cs
);
3697 static void dump_gdi_font_list(void)
3700 struct list
*elem_ptr
;
3702 TRACE("---------- gdiFont Cache ----------\n");
3703 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3704 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3705 TRACE("gdiFont=%p %s %d\n",
3706 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3709 TRACE("---------- Unused gdiFont Cache ----------\n");
3710 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3711 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3712 TRACE("gdiFont=%p %s %d\n",
3713 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3717 /*************************************************************
3718 * WineEngDestroyFontInstance
3720 * free the gdiFont associated with this handle
3723 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3728 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3732 EnterCriticalSection( &freetype_cs
);
3734 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3736 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3737 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3738 if(hflist
->hfont
== handle
)
3740 TRACE("removing child font %p from child list\n", gdiFont
);
3741 list_remove(&gdiFont
->entry
);
3742 LeaveCriticalSection( &freetype_cs
);
3747 TRACE("destroying hfont=%p\n", handle
);
3749 dump_gdi_font_list();
3751 font_elem_ptr
= list_head(&gdi_font_list
);
3752 while(font_elem_ptr
) {
3753 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3754 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3756 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3757 while(hfontlist_elem_ptr
) {
3758 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3759 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3760 if(hflist
->hfont
== handle
) {
3761 list_remove(&hflist
->entry
);
3762 HeapFree(GetProcessHeap(), 0, hflist
);
3766 if(list_empty(&gdiFont
->hfontlist
)) {
3767 TRACE("Moving to Unused list\n");
3768 list_remove(&gdiFont
->entry
);
3769 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3774 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3775 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3776 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3777 while(font_elem_ptr
) {
3778 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3779 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3780 TRACE("freeing %p\n", gdiFont
);
3781 list_remove(&gdiFont
->entry
);
3784 LeaveCriticalSection( &freetype_cs
);
3788 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3789 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3794 if (face
->cached_enum_data
)
3797 *pelf
= face
->cached_enum_data
->elf
;
3798 *pntm
= face
->cached_enum_data
->ntm
;
3799 *ptype
= face
->cached_enum_data
->type
;
3803 font
= alloc_font();
3805 if(face
->scalable
) {
3806 height
= -2048; /* 2048 is the most common em size */
3809 height
= face
->size
.y_ppem
>> 6;
3810 width
= face
->size
.x_ppem
>> 6;
3812 font
->scale_y
= 1.0;
3814 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3820 font
->name
= strdupW(face
->family
->FamilyName
);
3821 font
->ntmFlags
= face
->ntmFlags
;
3823 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3825 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3827 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3829 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3830 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3832 lstrcpynW(pelf
->elfFullName
,
3833 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3835 lstrcpynW(pelf
->elfStyle
,
3836 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3841 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3843 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3845 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3846 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3847 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3850 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3851 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3852 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3853 pntm
->ntmFontSig
= face
->fs
;
3855 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3857 pelf
->elfLogFont
.lfEscapement
= 0;
3858 pelf
->elfLogFont
.lfOrientation
= 0;
3859 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3860 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3861 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3862 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3863 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3864 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3865 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3866 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3867 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3868 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3869 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3872 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3873 *ptype
|= TRUETYPE_FONTTYPE
;
3874 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3875 *ptype
|= DEVICE_FONTTYPE
;
3876 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3877 *ptype
|= RASTER_FONTTYPE
;
3879 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3880 if (face
->cached_enum_data
)
3882 face
->cached_enum_data
->elf
= *pelf
;
3883 face
->cached_enum_data
->ntm
= *pntm
;
3884 face
->cached_enum_data
->type
= *ptype
;
3890 /*************************************************************
3894 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3898 struct list
*family_elem_ptr
, *face_elem_ptr
;
3900 NEWTEXTMETRICEXW ntm
;
3909 lf
.lfCharSet
= DEFAULT_CHARSET
;
3910 lf
.lfPitchAndFamily
= 0;
3911 lf
.lfFaceName
[0] = 0;
3915 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3918 EnterCriticalSection( &freetype_cs
);
3919 if(plf
->lfFaceName
[0]) {
3921 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3924 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3925 debugstr_w(psub
->to
.name
));
3927 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3931 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3932 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3933 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3934 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3935 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3936 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3937 for(i
= 0; i
< 32; i
++) {
3938 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3939 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3940 strcpyW(elf
.elfScript
, OEM_DOSW
);
3941 i
= 32; /* break out of loop */
3942 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3945 fs
.fsCsb
[0] = 1L << i
;
3947 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3949 csi
.ciCharset
= DEFAULT_CHARSET
;
3950 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3951 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3952 elf
.elfLogFont
.lfCharSet
=
3953 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3955 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3957 FIXME("Unknown elfscript for bit %d\n", i
);
3960 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3961 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3962 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3963 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3964 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3965 ntm
.ntmTm
.ntmFlags
);
3966 /* release section before callback (FIXME) */
3967 LeaveCriticalSection( &freetype_cs
);
3968 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3969 EnterCriticalSection( &freetype_cs
);
3975 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3976 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3977 face_elem_ptr
= list_head(&family
->faces
);
3978 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3979 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3980 for(i
= 0; i
< 32; i
++) {
3981 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3982 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3983 strcpyW(elf
.elfScript
, OEM_DOSW
);
3984 i
= 32; /* break out of loop */
3985 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3988 fs
.fsCsb
[0] = 1L << i
;
3990 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3992 csi
.ciCharset
= DEFAULT_CHARSET
;
3993 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3994 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3995 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3998 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
4000 FIXME("Unknown elfscript for bit %d\n", i
);
4003 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4004 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4005 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4006 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
4007 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4008 ntm
.ntmTm
.ntmFlags
);
4009 /* release section before callback (FIXME) */
4010 LeaveCriticalSection( &freetype_cs
);
4011 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
4012 EnterCriticalSection( &freetype_cs
);
4016 LeaveCriticalSection( &freetype_cs
);
4020 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4022 pt
->x
.value
= vec
->x
>> 6;
4023 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4024 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4025 pt
->y
.value
= vec
->y
>> 6;
4026 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4027 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4031 /***************************************************
4032 * According to the MSDN documentation on WideCharToMultiByte,
4033 * certain codepages cannot set the default_used parameter.
4034 * This returns TRUE if the codepage can set that parameter, false else
4035 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4037 static BOOL
codepage_sets_default_used(UINT codepage
)
4051 * GSUB Table handling functions
4054 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4056 const GSUB_CoverageFormat1
* cf1
;
4060 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4062 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4064 TRACE("Coverage Format 1, %i glyphs\n",count
);
4065 for (i
= 0; i
< count
; i
++)
4066 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4070 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4072 const GSUB_CoverageFormat2
* cf2
;
4075 cf2
= (GSUB_CoverageFormat2
*)cf1
;
4077 count
= GET_BE_WORD(cf2
->RangeCount
);
4078 TRACE("Coverage Format 2, %i ranges\n",count
);
4079 for (i
= 0; i
< count
; i
++)
4081 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4083 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4084 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4086 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4087 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4093 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4098 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4100 const GSUB_ScriptList
*script
;
4101 const GSUB_Script
*deflt
= NULL
;
4103 script
= (GSUB_ScriptList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->ScriptList
));
4105 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4106 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4108 const GSUB_Script
*scr
;
4111 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4112 scr
= (GSUB_Script
*)((LPBYTE
)script
+ offset
);
4114 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4116 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4122 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4126 const GSUB_LangSys
*Lang
;
4128 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4130 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4132 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4133 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4135 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4138 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4141 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4147 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4150 const GSUB_FeatureList
*feature
;
4151 feature
= (GSUB_FeatureList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->FeatureList
));
4153 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4154 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4156 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4157 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4159 const GSUB_Feature
*feat
;
4160 feat
= (GSUB_Feature
*)((LPBYTE
)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4167 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4171 const GSUB_LookupList
*lookup
;
4172 lookup
= (GSUB_LookupList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->LookupList
));
4174 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4175 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4177 const GSUB_LookupTable
*look
;
4178 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4179 look
= (GSUB_LookupTable
*)((LPBYTE
)lookup
+ offset
);
4180 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4181 if (GET_BE_WORD(look
->LookupType
) != 1)
4182 FIXME("We only handle SubType 1\n");
4187 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4189 const GSUB_SingleSubstFormat1
*ssf1
;
4190 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4191 ssf1
= (GSUB_SingleSubstFormat1
*)((LPBYTE
)look
+offset
);
4192 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4194 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4195 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4196 if (GSUB_is_glyph_covered((LPBYTE
)ssf1
+offset
, glyph
) != -1)
4198 TRACE(" Glyph 0x%x ->",glyph
);
4199 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4200 TRACE(" 0x%x\n",glyph
);
4205 const GSUB_SingleSubstFormat2
*ssf2
;
4209 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
4210 offset
= GET_BE_WORD(ssf1
->Coverage
);
4211 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4212 index
= GSUB_is_glyph_covered((LPBYTE
)ssf2
+offset
, glyph
);
4213 TRACE(" Coverage index %i\n",index
);
4216 TRACE(" Glyph is 0x%x ->",glyph
);
4217 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4218 TRACE("0x%x\n",glyph
);
4227 static const char* get_opentype_script(const GdiFont
*font
)
4230 * I am not sure if this is the correct way to generate our script tag
4233 switch (font
->charset
)
4235 case ANSI_CHARSET
: return "latn";
4236 case BALTIC_CHARSET
: return "latn"; /* ?? */
4237 case CHINESEBIG5_CHARSET
: return "hani";
4238 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4239 case GB2312_CHARSET
: return "hani";
4240 case GREEK_CHARSET
: return "grek";
4241 case HANGUL_CHARSET
: return "hang";
4242 case RUSSIAN_CHARSET
: return "cyrl";
4243 case SHIFTJIS_CHARSET
: return "kana";
4244 case TURKISH_CHARSET
: return "latn"; /* ?? */
4245 case VIETNAMESE_CHARSET
: return "latn";
4246 case JOHAB_CHARSET
: return "latn"; /* ?? */
4247 case ARABIC_CHARSET
: return "arab";
4248 case HEBREW_CHARSET
: return "hebr";
4249 case THAI_CHARSET
: return "thai";
4250 default: return "latn";
4254 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4256 const GSUB_Header
*header
;
4257 const GSUB_Script
*script
;
4258 const GSUB_LangSys
*language
;
4259 const GSUB_Feature
*feature
;
4261 if (!font
->GSUB_Table
)
4264 header
= font
->GSUB_Table
;
4266 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4269 TRACE("Script not found\n");
4272 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4275 TRACE("Language not found\n");
4278 feature
= GSUB_get_feature(header
, language
, "vrt2");
4280 feature
= GSUB_get_feature(header
, language
, "vert");
4283 TRACE("vrt2/vert feature not found\n");
4286 return GSUB_apply_feature(header
, feature
, glyph
);
4289 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4293 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4294 WCHAR wc
= (WCHAR
)glyph
;
4296 BOOL
*default_used_pointer
;
4299 default_used_pointer
= NULL
;
4300 default_used
= FALSE
;
4301 if (codepage_sets_default_used(font
->codepage
))
4302 default_used_pointer
= &default_used
;
4303 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4306 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4307 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4308 return get_GSUB_vert_glyph(font
,ret
);
4311 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4312 glyph
= glyph
+ 0xf000;
4313 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4314 return get_GSUB_vert_glyph(font
,glyphId
);
4317 /*************************************************************
4318 * WineEngGetGlyphIndices
4321 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4322 LPWORD pgi
, DWORD flags
)
4325 int default_char
= -1;
4327 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4329 for(i
= 0; i
< count
; i
++)
4331 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4334 if (default_char
== -1)
4336 if (FT_IS_SFNT(font
->ft_face
))
4338 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4339 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4344 WineEngGetTextMetrics(font
, &textm
);
4345 default_char
= textm
.tmDefaultChar
;
4348 pgi
[i
] = default_char
;
4354 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4356 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4357 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4360 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4362 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4363 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4366 /*************************************************************
4367 * WineEngGetGlyphOutline
4369 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4370 * except that the first parameter is the HWINEENGFONT of the font in
4371 * question rather than an HDC.
4374 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4375 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4378 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4379 FT_Face ft_face
= incoming_font
->ft_face
;
4380 GdiFont
*font
= incoming_font
;
4381 FT_UInt glyph_index
;
4382 DWORD width
, height
, pitch
, needed
= 0;
4383 FT_Bitmap ft_bitmap
;
4385 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4387 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4388 double widthRatio
= 1.0;
4389 FT_Matrix transMat
= identityMat
;
4390 FT_Matrix transMatUnrotated
;
4391 BOOL needsTransform
= FALSE
;
4392 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4393 UINT original_index
;
4395 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4396 buflen
, buf
, lpmat
);
4398 TRACE("font transform %f %f %f %f\n",
4399 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4400 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4403 EnterCriticalSection( &freetype_cs
);
4405 if(format
& GGO_GLYPH_INDEX
) {
4406 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4407 original_index
= glyph
;
4408 format
&= ~GGO_GLYPH_INDEX
;
4410 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4411 ft_face
= font
->ft_face
;
4412 original_index
= glyph_index
;
4415 if(format
& GGO_UNHINTED
) {
4416 load_flags
|= FT_LOAD_NO_HINTING
;
4417 format
&= ~GGO_UNHINTED
;
4420 /* tategaki never appears to happen to lower glyph index */
4421 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4424 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4425 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4426 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4427 font
->gmsize
* sizeof(GM
*));
4429 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4430 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
4432 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4433 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4434 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4435 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4436 LeaveCriticalSection( &freetype_cs
);
4437 return 1; /* FIXME */
4441 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4442 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4444 /* Scaling factor */
4449 WineEngGetTextMetrics(font
, &tm
);
4451 widthRatio
= (double)font
->aveWidth
;
4452 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4455 widthRatio
= font
->scale_y
;
4457 /* Scaling transform */
4458 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4461 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4464 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4466 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4467 needsTransform
= TRUE
;
4470 /* Slant transform */
4471 if (font
->fake_italic
) {
4474 slantMat
.xx
= (1 << 16);
4475 slantMat
.xy
= ((1 << 16) >> 2);
4477 slantMat
.yy
= (1 << 16);
4478 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4479 needsTransform
= TRUE
;
4482 /* Rotation transform */
4483 transMatUnrotated
= transMat
;
4484 if(font
->orientation
&& !tategaki
) {
4485 FT_Matrix rotationMat
;
4487 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4488 pFT_Vector_Unit(&vecAngle
, angle
);
4489 rotationMat
.xx
= vecAngle
.x
;
4490 rotationMat
.xy
= -vecAngle
.y
;
4491 rotationMat
.yx
= -rotationMat
.xy
;
4492 rotationMat
.yy
= rotationMat
.xx
;
4494 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4495 needsTransform
= TRUE
;
4498 /* World transform */
4499 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4502 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4503 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4504 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4505 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4506 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4507 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4508 needsTransform
= TRUE
;
4511 /* Extra transformation specified by caller */
4512 if (!is_identity_MAT2(lpmat
))
4515 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4516 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
4517 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
4518 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4519 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4520 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4521 needsTransform
= TRUE
;
4524 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4525 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4526 format
== GGO_GRAY8_BITMAP
))
4528 load_flags
|= FT_LOAD_NO_BITMAP
;
4531 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4534 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4535 LeaveCriticalSection( &freetype_cs
);
4539 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4540 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4542 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
) + 63) >> 6;
4544 bbx
= (right
- left
) >> 6;
4546 if(!needsTransform
) {
4547 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4548 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4549 ft_face
->glyph
->metrics
.height
) & -64;
4550 lpgm
->gmCellIncX
= adv
;
4551 lpgm
->gmCellIncY
= 0;
4555 for(xc
= 0; xc
< 2; xc
++) {
4556 for(yc
= 0; yc
< 2; yc
++) {
4557 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4558 xc
* ft_face
->glyph
->metrics
.width
);
4559 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4560 yc
* ft_face
->glyph
->metrics
.height
;
4561 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4562 pFT_Vector_Transform(&vec
, &transMat
);
4563 if(xc
== 0 && yc
== 0) {
4564 left
= right
= vec
.x
;
4565 top
= bottom
= vec
.y
;
4567 if(vec
.x
< left
) left
= vec
.x
;
4568 else if(vec
.x
> right
) right
= vec
.x
;
4569 if(vec
.y
< bottom
) bottom
= vec
.y
;
4570 else if(vec
.y
> top
) top
= vec
.y
;
4575 right
= (right
+ 63) & -64;
4576 bottom
= bottom
& -64;
4577 top
= (top
+ 63) & -64;
4579 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4580 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4582 pFT_Vector_Transform(&vec
, &transMat
);
4583 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4584 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4586 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4588 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4589 adv
= (vec
.x
+63) >> 6;
4591 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4592 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4593 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4594 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4596 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4597 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4598 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4600 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4601 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
4603 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4604 FONT_GM(font
,original_index
)->adv
= adv
;
4605 FONT_GM(font
,original_index
)->lsb
= lsb
;
4606 FONT_GM(font
,original_index
)->bbx
= bbx
;
4607 FONT_GM(font
,original_index
)->init
= TRUE
;
4610 if(format
== GGO_METRICS
)
4612 LeaveCriticalSection( &freetype_cs
);
4613 return 1; /* FIXME */
4616 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
4617 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4618 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4619 format
== GGO_GRAY8_BITMAP
))
4621 TRACE("loaded a bitmap\n");
4622 LeaveCriticalSection( &freetype_cs
);
4628 width
= lpgm
->gmBlackBoxX
;
4629 height
= lpgm
->gmBlackBoxY
;
4630 pitch
= ((width
+ 31) >> 5) << 2;
4631 needed
= pitch
* height
;
4633 if(!buf
|| !buflen
) break;
4635 switch(ft_face
->glyph
->format
) {
4636 case ft_glyph_format_bitmap
:
4638 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4639 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4640 INT h
= ft_face
->glyph
->bitmap
.rows
;
4642 memcpy(dst
, src
, w
);
4643 src
+= ft_face
->glyph
->bitmap
.pitch
;
4649 case ft_glyph_format_outline
:
4650 ft_bitmap
.width
= width
;
4651 ft_bitmap
.rows
= height
;
4652 ft_bitmap
.pitch
= pitch
;
4653 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4654 ft_bitmap
.buffer
= buf
;
4657 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4659 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4661 /* Note: FreeType will only set 'black' bits for us. */
4662 memset(buf
, 0, needed
);
4663 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4667 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4668 LeaveCriticalSection( &freetype_cs
);
4673 case GGO_GRAY2_BITMAP
:
4674 case GGO_GRAY4_BITMAP
:
4675 case GGO_GRAY8_BITMAP
:
4676 case WINE_GGO_GRAY16_BITMAP
:
4678 unsigned int mult
, row
, col
;
4681 width
= lpgm
->gmBlackBoxX
;
4682 height
= lpgm
->gmBlackBoxY
;
4683 pitch
= (width
+ 3) / 4 * 4;
4684 needed
= pitch
* height
;
4686 if(!buf
|| !buflen
) break;
4688 switch(ft_face
->glyph
->format
) {
4689 case ft_glyph_format_bitmap
:
4691 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4692 INT h
= ft_face
->glyph
->bitmap
.rows
;
4695 for(x
= 0; x
< pitch
; x
++)
4697 if(x
< ft_face
->glyph
->bitmap
.width
)
4698 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4702 src
+= ft_face
->glyph
->bitmap
.pitch
;
4705 LeaveCriticalSection( &freetype_cs
);
4708 case ft_glyph_format_outline
:
4710 ft_bitmap
.width
= width
;
4711 ft_bitmap
.rows
= height
;
4712 ft_bitmap
.pitch
= pitch
;
4713 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4714 ft_bitmap
.buffer
= buf
;
4717 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4719 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4721 memset(ft_bitmap
.buffer
, 0, buflen
);
4723 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4725 if(format
== GGO_GRAY2_BITMAP
)
4727 else if(format
== GGO_GRAY4_BITMAP
)
4729 else if(format
== GGO_GRAY8_BITMAP
)
4731 else /* format == WINE_GGO_GRAY16_BITMAP */
4733 LeaveCriticalSection( &freetype_cs
);
4739 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4740 LeaveCriticalSection( &freetype_cs
);
4745 for(row
= 0; row
< height
; row
++) {
4747 for(col
= 0; col
< width
; col
++, ptr
++) {
4748 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4755 case WINE_GGO_HRGB_BITMAP
:
4756 case WINE_GGO_HBGR_BITMAP
:
4757 case WINE_GGO_VRGB_BITMAP
:
4758 case WINE_GGO_VBGR_BITMAP
:
4759 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4761 switch (ft_face
->glyph
->format
)
4763 case FT_GLYPH_FORMAT_BITMAP
:
4768 width
= lpgm
->gmBlackBoxX
;
4769 height
= lpgm
->gmBlackBoxY
;
4771 needed
= pitch
* height
;
4773 if (!buf
|| !buflen
) break;
4775 memset(buf
, 0, buflen
);
4777 src
= ft_face
->glyph
->bitmap
.buffer
;
4778 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
4782 for (x
= 0; x
< width
; x
++)
4784 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
4785 ((unsigned int *)dst
)[x
] = ~0u;
4794 case FT_GLYPH_FORMAT_OUTLINE
:
4798 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
4799 INT x_shift
, y_shift
;
4801 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
4802 FT_Render_Mode render_mode
=
4803 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
4804 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
4806 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
4808 if ( render_mode
== FT_RENDER_MODE_LCD
)
4810 lpgm
->gmBlackBoxX
+= 2;
4811 lpgm
->gmptGlyphOrigin
.x
-= 1;
4815 lpgm
->gmBlackBoxY
+= 2;
4816 lpgm
->gmptGlyphOrigin
.y
+= 1;
4820 width
= lpgm
->gmBlackBoxX
;
4821 height
= lpgm
->gmBlackBoxY
;
4823 needed
= pitch
* height
;
4825 if (!buf
|| !buflen
) break;
4827 memset(buf
, 0, buflen
);
4829 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
4831 if ( needsTransform
)
4832 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
4834 if ( pFT_Library_SetLcdFilter
)
4835 pFT_Library_SetLcdFilter( library
, lcdfilter
);
4836 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
4838 src
= ft_face
->glyph
->bitmap
.buffer
;
4839 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
4840 src_width
= ft_face
->glyph
->bitmap
.width
;
4841 src_height
= ft_face
->glyph
->bitmap
.rows
;
4843 if ( render_mode
== FT_RENDER_MODE_LCD
)
4851 rgb_interval
= src_pitch
;
4856 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
4857 if ( x_shift
< 0 ) x_shift
= 0;
4858 if ( x_shift
+ (src_width
/ hmul
) > width
)
4859 x_shift
= width
- (src_width
/ hmul
);
4861 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
4862 if ( y_shift
< 0 ) y_shift
= 0;
4863 if ( y_shift
+ (src_height
/ vmul
) > height
)
4864 y_shift
= height
- (src_height
/ vmul
);
4866 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
4867 while ( src_height
)
4869 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
4873 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
4874 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
4875 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
4876 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
4880 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
4881 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
4882 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
4883 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
4886 src
+= src_pitch
* vmul
;
4895 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
4896 LeaveCriticalSection ( &freetype_cs
);
4903 LeaveCriticalSection( &freetype_cs
);
4909 int contour
, point
= 0, first_pt
;
4910 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4911 TTPOLYGONHEADER
*pph
;
4913 DWORD pph_start
, cpfx
, type
;
4915 if(buflen
== 0) buf
= NULL
;
4917 if (needsTransform
&& buf
) {
4918 pFT_Outline_Transform(outline
, &transMat
);
4921 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4923 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4926 pph
->dwType
= TT_POLYGON_TYPE
;
4927 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4929 needed
+= sizeof(*pph
);
4931 while(point
<= outline
->contours
[contour
]) {
4932 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4933 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4934 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4938 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4941 } while(point
<= outline
->contours
[contour
] &&
4942 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4943 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4944 /* At the end of a contour Windows adds the start point, but
4946 if(point
> outline
->contours
[contour
] &&
4947 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4949 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4951 } else if(point
<= outline
->contours
[contour
] &&
4952 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4953 /* add closing pt for bezier */
4955 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4963 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4966 pph
->cb
= needed
- pph_start
;
4972 /* Convert the quadratic Beziers to cubic Beziers.
4973 The parametric eqn for a cubic Bezier is, from PLRM:
4974 r(t) = at^3 + bt^2 + ct + r0
4975 with the control points:
4980 A quadratic Beizer has the form:
4981 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4983 So equating powers of t leads to:
4984 r1 = 2/3 p1 + 1/3 p0
4985 r2 = 2/3 p1 + 1/3 p2
4986 and of course r0 = p0, r3 = p2
4989 int contour
, point
= 0, first_pt
;
4990 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4991 TTPOLYGONHEADER
*pph
;
4993 DWORD pph_start
, cpfx
, type
;
4994 FT_Vector cubic_control
[4];
4995 if(buflen
== 0) buf
= NULL
;
4997 if (needsTransform
&& buf
) {
4998 pFT_Outline_Transform(outline
, &transMat
);
5001 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5003 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5006 pph
->dwType
= TT_POLYGON_TYPE
;
5007 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5009 needed
+= sizeof(*pph
);
5011 while(point
<= outline
->contours
[contour
]) {
5012 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5013 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5014 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5017 if(type
== TT_PRIM_LINE
) {
5019 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5023 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5026 /* FIXME: Possible optimization in endpoint calculation
5027 if there are two consecutive curves */
5028 cubic_control
[0] = outline
->points
[point
-1];
5029 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5030 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5031 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5032 cubic_control
[0].x
>>= 1;
5033 cubic_control
[0].y
>>= 1;
5035 if(point
+1 > outline
->contours
[contour
])
5036 cubic_control
[3] = outline
->points
[first_pt
];
5038 cubic_control
[3] = outline
->points
[point
+1];
5039 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5040 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5041 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5042 cubic_control
[3].x
>>= 1;
5043 cubic_control
[3].y
>>= 1;
5046 /* r1 = 1/3 p0 + 2/3 p1
5047 r2 = 1/3 p2 + 2/3 p1 */
5048 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5049 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5050 cubic_control
[2] = cubic_control
[1];
5051 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5052 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5053 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5054 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5056 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5057 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5058 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5063 } while(point
<= outline
->contours
[contour
] &&
5064 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5065 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5066 /* At the end of a contour Windows adds the start point,
5067 but only for Beziers and we've already done that.
5069 if(point
<= outline
->contours
[contour
] &&
5070 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5071 /* This is the closing pt of a bezier, but we've already
5072 added it, so just inc point and carry on */
5079 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5082 pph
->cb
= needed
- pph_start
;
5088 FIXME("Unsupported format %d\n", format
);
5089 LeaveCriticalSection( &freetype_cs
);
5092 LeaveCriticalSection( &freetype_cs
);
5096 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5098 FT_Face ft_face
= font
->ft_face
;
5099 #ifdef HAVE_FREETYPE_FTWINFNT_H
5100 FT_WinFNT_HeaderRec winfnt_header
;
5102 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5103 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5104 font
->potm
->otmSize
= size
;
5106 #define TM font->potm->otmTextMetrics
5107 #ifdef HAVE_FREETYPE_FTWINFNT_H
5108 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5110 TM
.tmHeight
= winfnt_header
.pixel_height
;
5111 TM
.tmAscent
= winfnt_header
.ascent
;
5112 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5113 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5114 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5115 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5116 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5117 TM
.tmWeight
= winfnt_header
.weight
;
5119 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5120 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5121 TM
.tmFirstChar
= winfnt_header
.first_char
;
5122 TM
.tmLastChar
= winfnt_header
.last_char
;
5123 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5124 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5125 TM
.tmItalic
= winfnt_header
.italic
;
5126 TM
.tmUnderlined
= font
->underline
;
5127 TM
.tmStruckOut
= font
->strikeout
;
5128 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5129 TM
.tmCharSet
= winfnt_header
.charset
;
5134 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5135 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5136 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5137 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5138 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5139 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5140 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5141 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5143 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5144 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5146 TM
.tmLastChar
= 255;
5147 TM
.tmDefaultChar
= 32;
5148 TM
.tmBreakChar
= 32;
5149 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5150 TM
.tmUnderlined
= font
->underline
;
5151 TM
.tmStruckOut
= font
->strikeout
;
5152 /* NB inverted meaning of TMPF_FIXED_PITCH */
5153 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5154 TM
.tmCharSet
= font
->charset
;
5162 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5164 double scale_x
, scale_y
;
5168 scale_x
= (double)font
->aveWidth
;
5169 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5172 scale_x
= font
->scale_y
;
5174 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5175 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5177 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5178 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5180 SCALE_Y(ptm
->tmHeight
);
5181 SCALE_Y(ptm
->tmAscent
);
5182 SCALE_Y(ptm
->tmDescent
);
5183 SCALE_Y(ptm
->tmInternalLeading
);
5184 SCALE_Y(ptm
->tmExternalLeading
);
5185 SCALE_Y(ptm
->tmOverhang
);
5187 SCALE_X(ptm
->tmAveCharWidth
);
5188 SCALE_X(ptm
->tmMaxCharWidth
);
5194 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5196 double scale_x
, scale_y
;
5200 scale_x
= (double)font
->aveWidth
;
5201 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5204 scale_x
= font
->scale_y
;
5206 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5207 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5209 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5211 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5212 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5214 SCALE_Y(potm
->otmAscent
);
5215 SCALE_Y(potm
->otmDescent
);
5216 SCALE_Y(potm
->otmLineGap
);
5217 SCALE_Y(potm
->otmsCapEmHeight
);
5218 SCALE_Y(potm
->otmsXHeight
);
5219 SCALE_Y(potm
->otmrcFontBox
.top
);
5220 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5221 SCALE_X(potm
->otmrcFontBox
.left
);
5222 SCALE_X(potm
->otmrcFontBox
.right
);
5223 SCALE_Y(potm
->otmMacAscent
);
5224 SCALE_Y(potm
->otmMacDescent
);
5225 SCALE_Y(potm
->otmMacLineGap
);
5226 SCALE_X(potm
->otmptSubscriptSize
.x
);
5227 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5228 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5229 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5230 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5231 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5232 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5233 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5234 SCALE_Y(potm
->otmsStrikeoutSize
);
5235 SCALE_Y(potm
->otmsStrikeoutPosition
);
5236 SCALE_Y(potm
->otmsUnderscoreSize
);
5237 SCALE_Y(potm
->otmsUnderscorePosition
);
5243 /*************************************************************
5244 * WineEngGetTextMetrics
5247 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5250 EnterCriticalSection( &freetype_cs
);
5252 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5253 if(!get_bitmap_text_metrics(font
))
5255 LeaveCriticalSection( &freetype_cs
);
5261 LeaveCriticalSection( &freetype_cs
);
5264 *ptm
= font
->potm
->otmTextMetrics
;
5265 scale_font_metrics(font
, ptm
);
5266 LeaveCriticalSection( &freetype_cs
);
5270 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5274 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5276 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
5282 /*************************************************************
5283 * WineEngGetOutlineTextMetrics
5286 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5287 OUTLINETEXTMETRICW
*potm
)
5289 FT_Face ft_face
= font
->ft_face
;
5290 UINT needed
, lenfam
, lensty
, ret
;
5292 TT_HoriHeader
*pHori
;
5293 TT_Postscript
*pPost
;
5294 FT_Fixed x_scale
, y_scale
;
5295 WCHAR
*family_nameW
, *style_nameW
;
5296 static const WCHAR spaceW
[] = {' ', '\0'};
5298 INT ascent
, descent
;
5300 TRACE("font=%p\n", font
);
5302 if(!FT_IS_SCALABLE(ft_face
))
5306 EnterCriticalSection( &freetype_cs
);
5309 if(cbSize
>= font
->potm
->otmSize
)
5311 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5312 scale_outline_font_metrics(font
, potm
);
5314 LeaveCriticalSection( &freetype_cs
);
5315 return font
->potm
->otmSize
;
5319 needed
= sizeof(*potm
);
5321 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5322 family_nameW
= strdupW(font
->name
);
5324 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5326 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5327 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5328 style_nameW
, lensty
/sizeof(WCHAR
));
5330 /* These names should be read from the TT name table */
5332 /* length of otmpFamilyName */
5335 /* length of otmpFaceName */
5336 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5337 needed
+= lenfam
; /* just the family name */
5339 needed
+= lenfam
+ lensty
; /* family + " " + style */
5342 /* length of otmpStyleName */
5345 /* length of otmpFullName */
5346 needed
+= lenfam
+ lensty
;
5349 x_scale
= ft_face
->size
->metrics
.x_scale
;
5350 y_scale
= ft_face
->size
->metrics
.y_scale
;
5352 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5354 FIXME("Can't find OS/2 table - not TT font?\n");
5359 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5361 FIXME("Can't find HHEA table - not TT font?\n");
5366 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5368 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",
5369 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5370 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5371 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5372 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5373 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5375 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5376 font
->potm
->otmSize
= needed
;
5378 #define TM font->potm->otmTextMetrics
5380 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5381 ascent
= pHori
->Ascender
;
5382 descent
= -pHori
->Descender
;
5384 ascent
= pOS2
->usWinAscent
;
5385 descent
= pOS2
->usWinDescent
;
5389 TM
.tmAscent
= font
->yMax
;
5390 TM
.tmDescent
= -font
->yMin
;
5391 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5393 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5394 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5395 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5396 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5399 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5402 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5404 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5405 ((ascent
+ descent
) -
5406 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5408 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5409 if (TM
.tmAveCharWidth
== 0) {
5410 TM
.tmAveCharWidth
= 1;
5412 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5413 TM
.tmWeight
= (font
->fake_bold
|| (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)) ? FW_BOLD
: FW_REGULAR
;
5415 TM
.tmDigitizedAspectX
= 300;
5416 TM
.tmDigitizedAspectY
= 300;
5417 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5418 * symbol range to 0 - f0ff
5421 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
5426 case 1257: /* Baltic */
5427 TM
.tmLastChar
= 0xf8fd;
5430 TM
.tmLastChar
= 0xf0ff;
5432 TM
.tmBreakChar
= 0x20;
5433 TM
.tmDefaultChar
= 0x1f;
5437 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
5438 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
5440 if(pOS2
->usFirstCharIndex
<= 1)
5441 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
5442 else if (pOS2
->usFirstCharIndex
> 0xff)
5443 TM
.tmBreakChar
= 0x20;
5445 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
5446 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
5448 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5449 TM
.tmUnderlined
= font
->underline
;
5450 TM
.tmStruckOut
= font
->strikeout
;
5452 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5453 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5454 (pOS2
->version
== 0xFFFFU
||
5455 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5456 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5458 TM
.tmPitchAndFamily
= 0;
5460 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
5462 case PAN_FAMILY_SCRIPT
:
5463 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5466 case PAN_FAMILY_DECORATIVE
:
5467 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5472 case PAN_FAMILY_TEXT_DISPLAY
:
5473 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
5474 /* which is clearly not what the panose spec says. */
5476 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
5477 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
5478 TM
.tmPitchAndFamily
= FF_MODERN
;
5481 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
5486 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5489 case PAN_SERIF_COVE
:
5490 case PAN_SERIF_OBTUSE_COVE
:
5491 case PAN_SERIF_SQUARE_COVE
:
5492 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
5493 case PAN_SERIF_SQUARE
:
5494 case PAN_SERIF_THIN
:
5495 case PAN_SERIF_BONE
:
5496 case PAN_SERIF_EXAGGERATED
:
5497 case PAN_SERIF_TRIANGLE
:
5498 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5501 case PAN_SERIF_NORMAL_SANS
:
5502 case PAN_SERIF_OBTUSE_SANS
:
5503 case PAN_SERIF_PERP_SANS
:
5504 case PAN_SERIF_FLARED
:
5505 case PAN_SERIF_ROUNDED
:
5506 TM
.tmPitchAndFamily
|= FF_SWISS
;
5513 if(FT_IS_SCALABLE(ft_face
))
5514 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5516 if(FT_IS_SFNT(ft_face
))
5518 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5519 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5521 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5524 TM
.tmCharSet
= font
->charset
;
5526 font
->potm
->otmFiller
= 0;
5527 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5528 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5529 font
->potm
->otmfsType
= pOS2
->fsType
;
5530 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5531 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5532 font
->potm
->otmItalicAngle
= 0; /* POST table */
5533 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5534 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5535 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5536 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5537 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5538 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5539 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5540 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5541 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5542 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5543 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5544 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5545 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5546 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5547 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5548 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5549 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5550 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5551 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5552 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5553 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5554 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5555 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5556 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5558 font
->potm
->otmsUnderscoreSize
= 0;
5559 font
->potm
->otmsUnderscorePosition
= 0;
5561 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5562 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5566 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5567 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5568 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5569 strcpyW((WCHAR
*)cp
, family_nameW
);
5571 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5572 strcpyW((WCHAR
*)cp
, style_nameW
);
5574 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5575 strcpyW((WCHAR
*)cp
, family_nameW
);
5576 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5577 strcatW((WCHAR
*)cp
, spaceW
);
5578 strcatW((WCHAR
*)cp
, style_nameW
);
5579 cp
+= lenfam
+ lensty
;
5582 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5583 strcpyW((WCHAR
*)cp
, family_nameW
);
5584 strcatW((WCHAR
*)cp
, spaceW
);
5585 strcatW((WCHAR
*)cp
, style_nameW
);
5588 if(potm
&& needed
<= cbSize
)
5590 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5591 scale_outline_font_metrics(font
, potm
);
5595 HeapFree(GetProcessHeap(), 0, style_nameW
);
5596 HeapFree(GetProcessHeap(), 0, family_nameW
);
5598 LeaveCriticalSection( &freetype_cs
);
5602 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5604 HFONTLIST
*hfontlist
;
5605 child
->font
= alloc_font();
5606 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5607 if(!child
->font
->ft_face
)
5609 free_font(child
->font
);
5614 child
->font
->font_desc
= font
->font_desc
;
5615 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5616 child
->font
->orientation
= font
->orientation
;
5617 child
->font
->scale_y
= font
->scale_y
;
5618 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5619 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5620 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5621 child
->font
->base_font
= font
;
5622 list_add_head(&child_font_list
, &child
->font
->entry
);
5623 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5627 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5630 CHILD_FONT
*child_font
;
5633 font
= font
->base_font
;
5635 *linked_font
= font
;
5637 if((*glyph
= get_glyph_index(font
, c
)))
5640 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5642 if(!child_font
->font
)
5643 if(!load_child_font(font
, child_font
))
5646 if(!child_font
->font
->ft_face
)
5648 g
= get_glyph_index(child_font
->font
, c
);
5652 *linked_font
= child_font
->font
;
5659 /*************************************************************
5660 * WineEngGetCharWidth
5663 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5666 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5669 FT_UInt glyph_index
;
5670 GdiFont
*linked_font
;
5672 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5675 EnterCriticalSection( &freetype_cs
);
5676 for(c
= firstChar
; c
<= lastChar
; c
++) {
5677 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5678 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5679 &gm
, 0, NULL
, &identity
);
5680 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5682 LeaveCriticalSection( &freetype_cs
);
5686 /*************************************************************
5687 * WineEngGetCharABCWidths
5690 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5693 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5696 FT_UInt glyph_index
;
5697 GdiFont
*linked_font
;
5699 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5701 if(!FT_IS_SCALABLE(font
->ft_face
))
5705 EnterCriticalSection( &freetype_cs
);
5707 for(c
= firstChar
; c
<= lastChar
; c
++) {
5708 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5709 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5710 &gm
, 0, NULL
, &identity
);
5711 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5712 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5713 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5714 FONT_GM(linked_font
,glyph_index
)->bbx
;
5716 LeaveCriticalSection( &freetype_cs
);
5720 /*************************************************************
5721 * WineEngGetCharABCWidthsI
5724 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5727 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5730 FT_UInt glyph_index
;
5731 GdiFont
*linked_font
;
5733 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5737 EnterCriticalSection( &freetype_cs
);
5739 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5741 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5742 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5743 &gm
, 0, NULL
, &identity
);
5744 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5745 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5746 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5747 - FONT_GM(linked_font
,c
)->bbx
;
5750 for(c
= 0; c
< count
; c
++) {
5751 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5752 &gm
, 0, NULL
, &identity
);
5753 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5754 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5755 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5756 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5759 LeaveCriticalSection( &freetype_cs
);
5763 /*************************************************************
5764 * WineEngGetTextExtentExPoint
5767 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5768 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5770 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5775 FT_UInt glyph_index
;
5776 GdiFont
*linked_font
;
5778 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
5782 EnterCriticalSection( &freetype_cs
);
5785 WineEngGetTextMetrics(font
, &tm
);
5786 size
->cy
= tm
.tmHeight
;
5788 for(idx
= 0; idx
< count
; idx
++) {
5789 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
5790 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5791 &gm
, 0, NULL
, &identity
);
5792 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
5794 if (! pnfit
|| ext
<= max_ext
) {
5804 LeaveCriticalSection( &freetype_cs
);
5805 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5809 /*************************************************************
5810 * WineEngGetTextExtentExPointI
5813 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5814 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5816 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5822 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
5825 EnterCriticalSection( &freetype_cs
);
5828 WineEngGetTextMetrics(font
, &tm
);
5829 size
->cy
= tm
.tmHeight
;
5831 for(idx
= 0; idx
< count
; idx
++) {
5832 WineEngGetGlyphOutline(font
, indices
[idx
],
5833 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
5835 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
5837 if (! pnfit
|| ext
<= max_ext
) {
5847 LeaveCriticalSection( &freetype_cs
);
5848 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5852 /*************************************************************
5853 * WineEngGetFontData
5856 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5859 FT_Face ft_face
= font
->ft_face
;
5863 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5864 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
5865 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
5867 if(!FT_IS_SFNT(ft_face
))
5875 if(table
) { /* MS tags differ in endianness from FT ones */
5876 table
= table
>> 24 | table
<< 24 |
5877 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
5880 /* make sure value of len is the value freetype says it needs */
5883 FT_ULong needed
= 0;
5884 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
5885 if( !err
&& needed
< len
) len
= needed
;
5887 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
5890 TRACE("Can't find table %c%c%c%c\n",
5891 /* bytes were reversed */
5892 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
5893 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
5899 /*************************************************************
5900 * WineEngGetTextFace
5903 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5905 INT n
= strlenW(font
->name
) + 1;
5907 lstrcpynW(str
, font
->name
, count
);
5908 return min(count
, n
);
5913 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5915 if (fs
) *fs
= font
->fs
;
5916 return font
->charset
;
5919 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5921 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
5922 struct list
*first_hfont
;
5926 EnterCriticalSection( &freetype_cs
);
5927 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
5928 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
5929 if(font
== linked_font
)
5930 *new_hfont
= dc
->hFont
;
5933 first_hfont
= list_head(&linked_font
->hfontlist
);
5934 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
5936 LeaveCriticalSection( &freetype_cs
);
5940 /* Retrieve a list of supported Unicode ranges for a given font.
5941 * Can be called with NULL gs to calculate the buffer size. Returns
5942 * the number of ranges found.
5944 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
5946 DWORD num_ranges
= 0;
5948 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5951 FT_ULong char_code
, char_code_prev
;
5954 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
5956 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5957 face
->num_glyphs
, glyph_code
, char_code
);
5959 if (!glyph_code
) return 0;
5963 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
5964 gs
->ranges
[0].cGlyphs
= 0;
5965 gs
->cGlyphsSupported
= 0;
5971 if (char_code
< char_code_prev
)
5973 ERR("expected increasing char code from FT_Get_Next_Char\n");
5976 if (char_code
- char_code_prev
> 1)
5981 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
5982 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
5983 gs
->cGlyphsSupported
++;
5988 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
5989 gs
->cGlyphsSupported
++;
5991 char_code_prev
= char_code
;
5992 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
5996 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6001 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6004 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
6006 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6009 glyphset
->cbThis
= size
;
6010 glyphset
->cRanges
= num_ranges
;
6015 /*************************************************************
6018 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6022 EnterCriticalSection( &freetype_cs
);
6023 ret
= !list_empty(&font
->child_fonts
);
6024 LeaveCriticalSection( &freetype_cs
);
6028 static BOOL
is_hinting_enabled(void)
6030 /* Use the >= 2.2.0 function if available */
6031 if(pFT_Get_TrueType_Engine_Type
)
6033 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6034 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6036 #ifdef FT_DRIVER_HAS_HINTER
6041 /* otherwise if we've been compiled with < 2.2.0 headers
6042 use the internal macro */
6043 mod
= pFT_Get_Module(library
, "truetype");
6044 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6052 static BOOL
is_subpixel_rendering_enabled( void )
6054 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6055 return pFT_Library_SetLcdFilter
&&
6056 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6062 /*************************************************************************
6063 * GetRasterizerCaps (GDI32.@)
6065 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6067 static int hinting
= -1;
6068 static int subpixel
= -1;
6072 hinting
= is_hinting_enabled();
6073 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6076 if ( subpixel
== -1 )
6078 subpixel
= is_subpixel_rendering_enabled();
6079 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6082 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6083 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6085 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6086 lprs
->nLanguageID
= 0;
6090 /*************************************************************
6091 * WineEngRealizationInfo
6093 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6095 FIXME("(%p, %p): stub!\n", font
, info
);
6098 if(FT_IS_SCALABLE(font
->ft_face
))
6101 info
->cache_num
= font
->cache_num
;
6102 info
->unknown2
= -1;
6106 /*************************************************************************
6107 * Kerning support for TrueType fonts
6109 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6111 struct TT_kern_table
6117 struct TT_kern_subtable
6126 USHORT horizontal
: 1;
6128 USHORT cross_stream
: 1;
6129 USHORT override
: 1;
6130 USHORT reserved1
: 4;
6136 struct TT_format0_kern_subtable
6140 USHORT entrySelector
;
6151 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6152 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6153 const USHORT
*glyph_to_char
,
6154 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6157 const struct TT_kern_pair
*tt_kern_pair
;
6159 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6161 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6163 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6164 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6165 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6167 if (!kern_pair
|| !cPairs
)
6170 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6172 nPairs
= min(nPairs
, cPairs
);
6174 for (i
= 0; i
< nPairs
; i
++)
6176 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6177 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6178 /* this algorithm appears to better match what Windows does */
6179 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6180 if (kern_pair
->iKernAmount
< 0)
6182 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6183 kern_pair
->iKernAmount
-= font
->ppem
;
6185 else if (kern_pair
->iKernAmount
> 0)
6187 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6188 kern_pair
->iKernAmount
+= font
->ppem
;
6190 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6192 TRACE("left %u right %u value %d\n",
6193 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6197 TRACE("copied %u entries\n", nPairs
);
6201 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6205 const struct TT_kern_table
*tt_kern_table
;
6206 const struct TT_kern_subtable
*tt_kern_subtable
;
6208 USHORT
*glyph_to_char
;
6211 EnterCriticalSection( &freetype_cs
);
6212 if (font
->total_kern_pairs
!= (DWORD
)-1)
6214 if (cPairs
&& kern_pair
)
6216 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6217 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6218 LeaveCriticalSection( &freetype_cs
);
6221 LeaveCriticalSection( &freetype_cs
);
6222 return font
->total_kern_pairs
;
6225 font
->total_kern_pairs
= 0;
6227 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6229 if (length
== GDI_ERROR
)
6231 TRACE("no kerning data in the font\n");
6232 LeaveCriticalSection( &freetype_cs
);
6236 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6239 WARN("Out of memory\n");
6240 LeaveCriticalSection( &freetype_cs
);
6244 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6246 /* build a glyph index to char code map */
6247 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6250 WARN("Out of memory allocating a glyph index to char code map\n");
6251 HeapFree(GetProcessHeap(), 0, buf
);
6252 LeaveCriticalSection( &freetype_cs
);
6256 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6262 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6264 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6265 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6269 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6271 /* FIXME: This doesn't match what Windows does: it does some fancy
6272 * things with duplicate glyph index to char code mappings, while
6273 * we just avoid overriding existing entries.
6275 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6276 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6278 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6285 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6286 for (n
= 0; n
<= 65535; n
++)
6287 glyph_to_char
[n
] = (USHORT
)n
;
6290 tt_kern_table
= buf
;
6291 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6292 TRACE("version %u, nTables %u\n",
6293 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6295 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6297 for (i
= 0; i
< nTables
; i
++)
6299 struct TT_kern_subtable tt_kern_subtable_copy
;
6301 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6302 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6303 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6305 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6306 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6307 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6309 /* According to the TrueType specification this is the only format
6310 * that will be properly interpreted by Windows and OS/2
6312 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6314 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6316 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6317 glyph_to_char
, NULL
, 0);
6318 font
->total_kern_pairs
+= new_chunk
;
6320 if (!font
->kern_pairs
)
6321 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6322 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6324 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6325 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6327 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6328 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6331 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6333 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6336 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6337 HeapFree(GetProcessHeap(), 0, buf
);
6339 if (cPairs
&& kern_pair
)
6341 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6342 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6343 LeaveCriticalSection( &freetype_cs
);
6346 LeaveCriticalSection( &freetype_cs
);
6347 return font
->total_kern_pairs
;
6350 #else /* HAVE_FREETYPE */
6352 /*************************************************************************/
6354 BOOL
WineEngInit(void)
6358 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6362 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6367 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6372 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6373 LPWORD pgi
, DWORD flags
)
6378 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6379 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6382 ERR("called but we don't have FreeType\n");
6386 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6388 ERR("called but we don't have FreeType\n");
6392 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6393 OUTLINETEXTMETRICW
*potm
)
6395 ERR("called but we don't have FreeType\n");
6399 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6402 ERR("called but we don't have FreeType\n");
6406 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6409 ERR("called but we don't have FreeType\n");
6413 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6416 ERR("called but we don't have FreeType\n");
6420 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6421 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6423 ERR("called but we don't have FreeType\n");
6427 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6428 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6430 ERR("called but we don't have FreeType\n");
6434 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6437 ERR("called but we don't have FreeType\n");
6441 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6443 ERR("called but we don't have FreeType\n");
6447 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6453 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6459 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6465 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6468 return DEFAULT_CHARSET
;
6471 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6476 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6478 FIXME("(%p, %p): stub\n", font
, glyphset
);
6482 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6487 /*************************************************************************
6488 * GetRasterizerCaps (GDI32.@)
6490 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6492 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6494 lprs
->nLanguageID
= 0;
6498 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6500 ERR("called but we don't have FreeType\n");
6504 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6506 ERR("called but we don't have FreeType\n");
6510 #endif /* HAVE_FREETYPE */