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>
136 #ifndef HAVE_FT_TRUETYPEENGINETYPE
139 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
140 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
141 FT_TRUETYPE_ENGINE_TYPE_PATENTED
142 } FT_TrueTypeEngineType
;
145 static FT_Library library
= 0;
152 static FT_Version_t FT_Version
;
153 static DWORD FT_SimpleVersion
;
155 static void *ft_handle
= NULL
;
157 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
158 MAKE_FUNCPTR(FT_Vector_Unit
);
159 MAKE_FUNCPTR(FT_Done_Face
);
160 MAKE_FUNCPTR(FT_Get_Char_Index
);
161 MAKE_FUNCPTR(FT_Get_Module
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
165 MAKE_FUNCPTR(FT_Init_FreeType
);
166 MAKE_FUNCPTR(FT_Load_Glyph
);
167 MAKE_FUNCPTR(FT_Matrix_Multiply
);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
171 MAKE_FUNCPTR(FT_MulFix
);
173 MAKE_FUNCPTR(FT_New_Face
);
174 MAKE_FUNCPTR(FT_New_Memory_Face
);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
176 MAKE_FUNCPTR(FT_Outline_Transform
);
177 MAKE_FUNCPTR(FT_Outline_Translate
);
178 MAKE_FUNCPTR(FT_Select_Charmap
);
179 MAKE_FUNCPTR(FT_Set_Charmap
);
180 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
181 MAKE_FUNCPTR(FT_Vector_Transform
);
182 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
183 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
184 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
185 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
186 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
187 #ifdef HAVE_FREETYPE_FTWINFNT_H
188 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
191 #ifdef SONAME_LIBFONTCONFIG
192 #include <fontconfig/fontconfig.h>
193 MAKE_FUNCPTR(FcConfigGetCurrent
);
194 MAKE_FUNCPTR(FcFontList
);
195 MAKE_FUNCPTR(FcFontSetDestroy
);
196 MAKE_FUNCPTR(FcInit
);
197 MAKE_FUNCPTR(FcObjectSetAdd
);
198 MAKE_FUNCPTR(FcObjectSetCreate
);
199 MAKE_FUNCPTR(FcObjectSetDestroy
);
200 MAKE_FUNCPTR(FcPatternCreate
);
201 MAKE_FUNCPTR(FcPatternDestroy
);
202 MAKE_FUNCPTR(FcPatternGetBool
);
203 MAKE_FUNCPTR(FcPatternGetString
);
209 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
210 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
211 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
214 #ifndef ft_encoding_none
215 #define FT_ENCODING_NONE ft_encoding_none
217 #ifndef ft_encoding_ms_symbol
218 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #ifndef ft_encoding_unicode
221 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #ifndef ft_encoding_apple_roman
224 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
227 #ifdef WORDS_BIGENDIAN
228 #define GET_BE_WORD(x) (x)
230 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
233 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
240 FT_Short internal_leading
;
243 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
244 So to let this compile on older versions of FreeType we'll define the
245 new structure here. */
247 FT_Short height
, width
;
248 FT_Pos size
, x_ppem
, y_ppem
;
254 NEWTEXTMETRICEXW ntm
;
258 typedef struct tagFace
{
263 DWORD font_data_size
;
266 FONTSIGNATURE fs_links
;
268 FT_Fixed font_version
;
270 Bitmap_Size size
; /* set if face is a bitmap */
271 BOOL external
; /* TRUE if we should manually add this font to the registry */
272 struct tagFamily
*family
;
273 /* Cached data for Enum */
274 struct enum_data
*cached_enum_data
;
277 typedef struct tagFamily
{
279 const WCHAR
*FamilyName
;
285 INT adv
; /* These three hold to widths of the unrotated chars */
303 typedef struct tagHFONTLIST
{
318 struct list hfontlist
;
319 OUTLINETEXTMETRICW
*potm
;
320 DWORD total_kern_pairs
;
321 KERNINGPAIR
*kern_pairs
;
322 struct list child_fonts
;
324 /* the following members can be accessed without locking, they are never modified after creation */
326 struct font_mapping
*mapping
;
349 const WCHAR
*font_name
;
353 #define GM_BLOCK_SIZE 128
354 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
356 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
357 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
358 #define UNUSED_CACHE_SIZE 10
359 static struct list child_font_list
= LIST_INIT(child_font_list
);
360 static struct list system_links
= LIST_INIT(system_links
);
362 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
364 static struct list font_list
= LIST_INIT(font_list
);
366 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
367 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
368 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
370 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
371 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
372 'W','i','n','d','o','w','s','\\',
373 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
374 'F','o','n','t','s','\0'};
376 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
377 'W','i','n','d','o','w','s',' ','N','T','\\',
378 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
379 'F','o','n','t','s','\0'};
381 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
382 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
383 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
384 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
386 static const WCHAR
* const SystemFontValues
[4] = {
393 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
394 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
396 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
397 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
398 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
399 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
400 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
401 'E','u','r','o','p','e','a','n','\0'};
402 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
403 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
404 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
405 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
406 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
407 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
408 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
409 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
410 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
411 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
412 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
413 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
415 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
425 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
433 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
442 typedef struct tagFontSubst
{
458 static struct list mappings_list
= LIST_INIT( mappings_list
);
460 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
462 static CRITICAL_SECTION freetype_cs
;
463 static CRITICAL_SECTION_DEBUG critsect_debug
=
466 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
467 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
469 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
471 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
473 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
474 static BOOL use_default_fallback
= FALSE
;
476 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
478 /****************************************
479 * Notes on .fon files
481 * The fonts System, FixedSys and Terminal are special. There are typically multiple
482 * versions installed for different resolutions and codepages. Windows stores which one to use
483 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
485 * FIXEDFON.FON FixedSys
487 * OEMFONT.FON Terminal
488 * LogPixels Current dpi set by the display control panel applet
489 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
490 * also has a LogPixels value that appears to mirror this)
492 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
493 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
494 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
495 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
496 * so that makes sense.
498 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
499 * to be mapped into the registry on Windows 2000 at least).
502 * ega80woa.fon=ega80850.fon
503 * ega40woa.fon=ega40850.fon
504 * cga80woa.fon=cga80850.fon
505 * cga40woa.fon=cga40850.fon
508 /* These are all structures needed for the GSUB table */
510 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
511 #define TATEGAKI_LOWER_BOUND 0x02F1
527 GSUB_ScriptRecord ScriptRecord
[1];
533 } GSUB_LangSysRecord
;
538 GSUB_LangSysRecord LangSysRecord
[1];
542 WORD LookupOrder
; /* Reserved */
543 WORD ReqFeatureIndex
;
545 WORD FeatureIndex
[1];
551 } GSUB_FeatureRecord
;
555 GSUB_FeatureRecord FeatureRecord
[1];
559 WORD FeatureParams
; /* Reserved */
561 WORD LookupListIndex
[1];
580 } GSUB_CoverageFormat1
;
585 WORD StartCoverageIndex
;
591 GSUB_RangeRecord RangeRecord
[1];
592 } GSUB_CoverageFormat2
;
595 WORD SubstFormat
; /* = 1 */
598 } GSUB_SingleSubstFormat1
;
601 WORD SubstFormat
; /* = 2 */
605 }GSUB_SingleSubstFormat2
;
607 #ifdef HAVE_CARBON_CARBON_H
608 static char *find_cache_dir(void)
612 static char cached_path
[MAX_PATH
];
613 static const char *wine
= "/Wine", *fonts
= "/Fonts";
615 if(*cached_path
) return cached_path
;
617 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
620 WARN("can't create cached data folder\n");
623 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
626 WARN("can't create cached data path\n");
630 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
632 ERR("Could not create full path\n");
636 strcat(cached_path
, wine
);
638 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
640 WARN("Couldn't mkdir %s\n", cached_path
);
644 strcat(cached_path
, fonts
);
645 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
647 WARN("Couldn't mkdir %s\n", cached_path
);
654 /******************************************************************
657 * Extracts individual TrueType font files from a Mac suitcase font
658 * and saves them into the user's caches directory (see
660 * Returns a NULL terminated array of filenames.
662 * We do this because they are apps that try to read ttf files
663 * themselves and they don't like Mac suitcase files.
665 static char **expand_mac_font(const char *path
)
672 const char *filename
;
676 unsigned int size
, max_size
;
679 TRACE("path %s\n", path
);
681 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
684 WARN("failed to get ref\n");
688 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
691 TRACE("no data fork, so trying resource fork\n");
692 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
695 TRACE("unable to open resource fork\n");
702 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
705 CloseResFile(res_ref
);
709 out_dir
= find_cache_dir();
711 filename
= strrchr(path
, '/');
712 if(!filename
) filename
= path
;
715 /* output filename has the form out_dir/filename_%04x.ttf */
716 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
723 unsigned short *num_faces_ptr
, num_faces
, face
;
726 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
728 fond
= Get1IndResource(fond_res
, idx
);
730 TRACE("got fond resource %d\n", idx
);
733 fam_rec
= *(FamRec
**)fond
;
734 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
735 num_faces
= GET_BE_WORD(*num_faces_ptr
);
737 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
738 TRACE("num faces %04x\n", num_faces
);
739 for(face
= 0; face
< num_faces
; face
++, assoc
++)
742 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
743 unsigned short size
, font_id
;
746 size
= GET_BE_WORD(assoc
->fontSize
);
747 font_id
= GET_BE_WORD(assoc
->fontID
);
750 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
754 TRACE("trying to load sfnt id %04x\n", font_id
);
755 sfnt
= GetResource(sfnt_res
, font_id
);
758 TRACE("can't get sfnt resource %04x\n", font_id
);
762 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
767 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
769 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
770 if(fd
!= -1 || errno
== EEXIST
)
774 unsigned char *sfnt_data
;
777 sfnt_data
= *(unsigned char**)sfnt
;
778 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
782 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
785 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
787 ret
.array
[ret
.size
++] = output
;
791 WARN("unable to create %s\n", output
);
792 HeapFree(GetProcessHeap(), 0, output
);
795 ReleaseResource(sfnt
);
798 ReleaseResource(fond
);
801 CloseResFile(res_ref
);
806 #endif /* HAVE_CARBON_CARBON_H */
808 static inline BOOL
is_win9x(void)
810 return GetVersion() & 0x80000000;
813 This function builds an FT_Fixed from a double. It fails if the absolute
814 value of the float number is greater than 32768.
816 static inline FT_Fixed
FT_FixedFromFloat(double f
)
822 This function builds an FT_Fixed from a FIXED. It simply put f.value
823 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
825 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
827 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
831 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
836 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
837 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
839 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
840 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
842 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
844 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
846 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
850 file
= strrchr(face
->file
, '/');
855 if(!strcasecmp(file
, file_nameA
))
857 HeapFree(GetProcessHeap(), 0, file_nameA
);
862 HeapFree(GetProcessHeap(), 0, file_nameA
);
866 static Family
*find_family_from_name(const WCHAR
*name
)
870 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
872 if(!strcmpiW(family
->FamilyName
, name
))
879 static void DumpSubstList(void)
883 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
885 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
886 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
887 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
889 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
890 debugstr_w(psub
->to
.name
));
895 static LPWSTR
strdupW(LPCWSTR p
)
898 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
899 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
904 static LPSTR
strdupA(LPCSTR p
)
907 DWORD len
= (strlen(p
) + 1);
908 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
913 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
918 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
920 if(!strcmpiW(element
->from
.name
, from_name
) &&
921 (element
->from
.charset
== from_charset
||
922 element
->from
.charset
== -1))
929 #define ADD_FONT_SUBST_FORCE 1
931 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
933 FontSubst
*from_exist
, *to_exist
;
935 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
937 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
939 list_remove(&from_exist
->entry
);
940 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
941 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
942 HeapFree(GetProcessHeap(), 0, from_exist
);
948 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
952 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
953 subst
->to
.name
= strdupW(to_exist
->to
.name
);
956 list_add_tail(subst_list
, &subst
->entry
);
961 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
962 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
963 HeapFree(GetProcessHeap(), 0, subst
);
967 static void split_subst_info(NameCs
*nc
, LPSTR str
)
969 CHAR
*p
= strrchr(str
, ',');
974 nc
->charset
= strtol(p
+1, NULL
, 10);
977 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
978 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
979 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
982 static void LoadSubstList(void)
986 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
990 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
991 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
992 &hkey
) == ERROR_SUCCESS
) {
994 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
995 &valuelen
, &datalen
, NULL
, NULL
);
997 valuelen
++; /* returned value doesn't include room for '\0' */
998 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
999 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1003 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1004 &dlen
) == ERROR_SUCCESS
) {
1005 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1007 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1008 split_subst_info(&psub
->from
, value
);
1009 split_subst_info(&psub
->to
, data
);
1011 /* Win 2000 doesn't allow mapping between different charsets
1012 or mapping of DEFAULT_CHARSET */
1013 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1014 psub
->to
.charset
== DEFAULT_CHARSET
) {
1015 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1016 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1017 HeapFree(GetProcessHeap(), 0, psub
);
1019 add_font_subst(&font_subst_list
, psub
, 0);
1021 /* reset dlen and vlen */
1025 HeapFree(GetProcessHeap(), 0, data
);
1026 HeapFree(GetProcessHeap(), 0, value
);
1032 /*****************************************************************
1033 * get_name_table_entry
1035 * Supply the platform, encoding, language and name ids in req
1036 * and if the name exists the function will fill in the string
1037 * and string_len members. The string is owned by FreeType so
1038 * don't free it. Returns TRUE if the name is found else FALSE.
1040 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1043 FT_UInt num_names
, name_index
;
1045 if(FT_IS_SFNT(ft_face
))
1047 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1049 for(name_index
= 0; name_index
< num_names
; name_index
++)
1051 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1053 if((name
.platform_id
== req
->platform_id
) &&
1054 (name
.encoding_id
== req
->encoding_id
) &&
1055 (name
.language_id
== req
->language_id
) &&
1056 (name
.name_id
== req
->name_id
))
1058 req
->string
= name
.string
;
1059 req
->string_len
= name
.string_len
;
1066 req
->string_len
= 0;
1070 static WCHAR
*get_familyname(FT_Face ft_face
)
1072 WCHAR
*family
= NULL
;
1075 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1076 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1077 name
.language_id
= GetUserDefaultLCID();
1078 name
.name_id
= TT_NAME_ID_FONT_FAMILY
;
1080 if(get_name_table_entry(ft_face
, &name
))
1084 /* String is not nul terminated and string_len is a byte length. */
1085 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1086 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1088 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1089 family
[i
] = GET_BE_WORD(*tmp
);
1092 TRACE("Got localised name %s\n", debugstr_w(family
));
1099 /*****************************************************************
1102 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1103 * of FreeType that don't export this function.
1106 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1111 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1112 if(pFT_Load_Sfnt_Table
)
1114 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1116 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1117 else /* Do it the hard way */
1119 TT_Face tt_face
= (TT_Face
) ft_face
;
1120 SFNT_Interface
*sfnt
;
1121 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1124 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1128 /* A field was added in the middle of the structure in 2.1.x */
1129 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1131 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1139 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1140 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1141 "Please upgrade your freetype library.\n");
1144 err
= FT_Err_Unimplemented_Feature
;
1150 static inline int TestStyles(DWORD flags
, DWORD styles
)
1152 return (flags
& styles
) == styles
;
1155 static int StyleOrdering(Face
*face
)
1157 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1159 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1161 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1163 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1166 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1167 debugstr_w(face
->family
->FamilyName
),
1168 debugstr_w(face
->StyleName
),
1174 /* Add a style of face to a font family using an ordering of the list such
1175 that regular fonts come before bold and italic, and single styles come
1176 before compound styles. */
1177 static void AddFaceToFamily(Face
*face
, Family
*family
)
1181 LIST_FOR_EACH( entry
, &family
->faces
)
1183 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1184 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1186 list_add_before( entry
, &face
->entry
);
1189 #define ADDFONT_EXTERNAL_FONT 0x01
1190 #define ADDFONT_FORCE_BITMAP 0x02
1191 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1195 TT_Header
*pHeader
= NULL
;
1196 WCHAR
*english_family
, *localised_family
, *StyleW
;
1200 struct list
*family_elem_ptr
, *face_elem_ptr
;
1202 FT_Long face_index
= 0, num_faces
;
1203 #ifdef HAVE_FREETYPE_FTWINFNT_H
1204 FT_WinFNT_HeaderRec winfnt_header
;
1206 int i
, bitmap_num
, internal_leading
;
1209 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1210 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1212 #ifdef HAVE_CARBON_CARBON_H
1213 if(file
&& !fake_family
)
1215 char **mac_list
= expand_mac_font(file
);
1218 BOOL had_one
= FALSE
;
1220 for(cursor
= mac_list
; *cursor
; cursor
++)
1223 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1224 HeapFree(GetProcessHeap(), 0, *cursor
);
1226 HeapFree(GetProcessHeap(), 0, mac_list
);
1231 #endif /* HAVE_CARBON_CARBON_H */
1234 char *family_name
= fake_family
;
1238 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1239 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1242 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1243 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1247 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1251 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*/
1252 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1253 pFT_Done_Face(ft_face
);
1257 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1258 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1259 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1260 pFT_Done_Face(ft_face
);
1264 if(FT_IS_SFNT(ft_face
))
1266 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1267 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1268 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1270 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1271 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1272 pFT_Done_Face(ft_face
);
1276 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1277 we don't want to load these. */
1278 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1282 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1284 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1285 pFT_Done_Face(ft_face
);
1291 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1292 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1293 pFT_Done_Face(ft_face
);
1297 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1299 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1300 pFT_Done_Face(ft_face
);
1306 localised_family
= get_familyname(ft_face
);
1307 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1309 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1310 HeapFree(GetProcessHeap(), 0, localised_family
);
1311 num_faces
= ft_face
->num_faces
;
1312 pFT_Done_Face(ft_face
);
1315 HeapFree(GetProcessHeap(), 0, localised_family
);
1319 family_name
= ft_face
->family_name
;
1323 My_FT_Bitmap_Size
*size
= NULL
;
1326 if(!FT_IS_SCALABLE(ft_face
))
1327 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1329 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1330 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1331 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1333 localised_family
= NULL
;
1335 localised_family
= get_familyname(ft_face
);
1336 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1337 HeapFree(GetProcessHeap(), 0, localised_family
);
1338 localised_family
= NULL
;
1343 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1344 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1345 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1350 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1351 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1352 list_init(&family
->faces
);
1353 list_add_tail(&font_list
, &family
->entry
);
1355 if(localised_family
) {
1356 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1357 subst
->from
.name
= strdupW(english_family
);
1358 subst
->from
.charset
= -1;
1359 subst
->to
.name
= strdupW(localised_family
);
1360 subst
->to
.charset
= -1;
1361 add_font_subst(&font_subst_list
, subst
, 0);
1364 HeapFree(GetProcessHeap(), 0, localised_family
);
1365 HeapFree(GetProcessHeap(), 0, english_family
);
1367 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1368 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1369 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1371 internal_leading
= 0;
1372 memset(&fs
, 0, sizeof(fs
));
1374 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1376 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1377 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1378 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1379 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1380 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1381 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1382 if(pOS2
->version
== 0) {
1385 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1386 fs
.fsCsb
[0] |= FS_LATIN1
;
1388 fs
.fsCsb
[0] |= FS_SYMBOL
;
1391 #ifdef HAVE_FREETYPE_FTWINFNT_H
1392 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1394 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1395 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1396 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1398 internal_leading
= winfnt_header
.internal_leading
;
1402 face_elem_ptr
= list_head(&family
->faces
);
1403 while(face_elem_ptr
) {
1404 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1405 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1406 if(!strcmpW(face
->StyleName
, StyleW
) &&
1407 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1408 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1409 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1410 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1413 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1414 HeapFree(GetProcessHeap(), 0, StyleW
);
1415 pFT_Done_Face(ft_face
);
1418 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1419 TRACE("Original font is newer so skipping this one\n");
1420 HeapFree(GetProcessHeap(), 0, StyleW
);
1421 pFT_Done_Face(ft_face
);
1424 TRACE("Replacing original with this one\n");
1425 list_remove(&face
->entry
);
1426 HeapFree(GetProcessHeap(), 0, face
->file
);
1427 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1428 HeapFree(GetProcessHeap(), 0, face
);
1433 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1434 face
->cached_enum_data
= NULL
;
1435 face
->StyleName
= StyleW
;
1438 face
->file
= strdupA(file
);
1439 face
->font_data_ptr
= NULL
;
1440 face
->font_data_size
= 0;
1445 face
->font_data_ptr
= font_data_ptr
;
1446 face
->font_data_size
= font_data_size
;
1448 face
->face_index
= face_index
;
1450 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1451 face
->ntmFlags
|= NTM_ITALIC
;
1452 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1453 face
->ntmFlags
|= NTM_BOLD
;
1454 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1455 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1456 face
->family
= family
;
1457 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1459 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1461 if(FT_IS_SCALABLE(ft_face
)) {
1462 memset(&face
->size
, 0, sizeof(face
->size
));
1463 face
->scalable
= TRUE
;
1465 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1466 size
->height
, size
->width
, size
->size
>> 6,
1467 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1468 face
->size
.height
= size
->height
;
1469 face
->size
.width
= size
->width
;
1470 face
->size
.size
= size
->size
;
1471 face
->size
.x_ppem
= size
->x_ppem
;
1472 face
->size
.y_ppem
= size
->y_ppem
;
1473 face
->size
.internal_leading
= internal_leading
;
1474 face
->scalable
= FALSE
;
1477 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1479 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1481 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1482 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1485 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1486 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1487 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1488 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1491 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1492 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1493 switch(ft_face
->charmaps
[i
]->encoding
) {
1494 case FT_ENCODING_UNICODE
:
1495 case FT_ENCODING_APPLE_ROMAN
:
1496 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1498 case FT_ENCODING_MS_SYMBOL
:
1499 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1507 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1508 have_installed_roman_font
= TRUE
;
1510 AddFaceToFamily(face
, family
);
1512 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1514 num_faces
= ft_face
->num_faces
;
1515 pFT_Done_Face(ft_face
);
1516 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1517 debugstr_w(StyleW
));
1518 } while(num_faces
> ++face_index
);
1522 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1524 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1527 static void DumpFontList(void)
1531 struct list
*family_elem_ptr
, *face_elem_ptr
;
1533 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1534 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1535 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1536 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1537 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1538 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1540 TRACE(" %d", face
->size
.height
);
1547 /***********************************************************
1548 * The replacement list is a way to map an entire font
1549 * family onto another family. For example adding
1551 * [HKCU\Software\Wine\Fonts\Replacements]
1552 * "Wingdings"="Winedings"
1554 * would enumerate the Winedings font both as Winedings and
1555 * Wingdings. However if a real Wingdings font is present the
1556 * replacement does not take place.
1559 static void LoadReplaceList(void)
1562 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1567 struct list
*family_elem_ptr
, *face_elem_ptr
;
1570 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1571 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1573 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1574 &valuelen
, &datalen
, NULL
, NULL
);
1576 valuelen
++; /* returned value doesn't include room for '\0' */
1577 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1578 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1582 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1583 &dlen
) == ERROR_SUCCESS
) {
1584 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1585 /* "NewName"="Oldname" */
1586 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1588 /* Find the old family and hence all of the font files
1590 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1591 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1592 if(!strcmpiW(family
->FamilyName
, data
)) {
1593 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1594 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1595 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1596 debugstr_w(face
->StyleName
), familyA
);
1597 /* Now add a new entry with the new family name */
1598 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1603 /* reset dlen and vlen */
1607 HeapFree(GetProcessHeap(), 0, data
);
1608 HeapFree(GetProcessHeap(), 0, value
);
1613 /*************************************************************
1616 static BOOL
init_system_links(void)
1618 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1619 'W','i','n','d','o','w','s',' ','N','T','\\',
1620 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1621 'S','y','s','t','e','m','L','i','n','k',0};
1624 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1625 WCHAR
*value
, *data
;
1626 WCHAR
*entry
, *next
;
1627 SYSTEM_LINKS
*font_link
, *system_font_link
;
1628 CHILD_FONT
*child_font
;
1629 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1630 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1631 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1637 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1639 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1640 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1641 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1642 val_len
= max_val
+ 1;
1643 data_len
= max_data
;
1645 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1647 TRACE("%s:\n", debugstr_w(value
));
1649 memset(&fs
, 0, sizeof(fs
));
1650 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1651 psub
= get_font_subst(&font_subst_list
, value
, -1);
1652 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1653 list_init(&font_link
->links
);
1654 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1657 CHILD_FONT
*child_font
;
1659 TRACE("\t%s\n", debugstr_w(entry
));
1661 next
= entry
+ strlenW(entry
) + 1;
1663 face_name
= strchrW(entry
, ',');
1667 while(isspaceW(*face_name
))
1670 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1672 face_name
= psub
->to
.name
;
1674 face
= find_face_from_filename(entry
, face_name
);
1677 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1681 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1682 child_font
->face
= face
;
1683 child_font
->font
= NULL
;
1684 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1685 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1686 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1687 list_add_tail(&font_link
->links
, &child_font
->entry
);
1689 family
= find_family_from_name(font_link
->font_name
);
1692 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1694 face
->fs_links
= fs
;
1697 list_add_tail(&system_links
, &font_link
->entry
);
1698 val_len
= max_val
+ 1;
1699 data_len
= max_data
;
1702 HeapFree(GetProcessHeap(), 0, value
);
1703 HeapFree(GetProcessHeap(), 0, data
);
1707 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1710 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1711 system_font_link
->font_name
= strdupW(System
);
1712 list_init(&system_font_link
->links
);
1714 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1717 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1718 child_font
->face
= face
;
1719 child_font
->font
= NULL
;
1720 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1721 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1723 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1725 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1727 CHILD_FONT
*font_link_entry
;
1728 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1730 CHILD_FONT
*new_child
;
1731 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1732 new_child
->face
= font_link_entry
->face
;
1733 new_child
->font
= NULL
;
1734 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1739 list_add_tail(&system_links
, &system_font_link
->entry
);
1743 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1746 struct dirent
*dent
;
1747 char path
[MAX_PATH
];
1749 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1751 dir
= opendir(dirname
);
1753 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1756 while((dent
= readdir(dir
)) != NULL
) {
1757 struct stat statbuf
;
1759 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1762 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1764 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1766 if(stat(path
, &statbuf
) == -1)
1768 WARN("Can't stat %s\n", debugstr_a(path
));
1771 if(S_ISDIR(statbuf
.st_mode
))
1772 ReadFontDir(path
, external_fonts
);
1774 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1780 static void load_fontconfig_fonts(void)
1782 #ifdef SONAME_LIBFONTCONFIG
1783 void *fc_handle
= NULL
;
1792 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1794 TRACE("Wine cannot find the fontconfig library (%s).\n",
1795 SONAME_LIBFONTCONFIG
);
1798 #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;}
1799 LOAD_FUNCPTR(FcConfigGetCurrent
);
1800 LOAD_FUNCPTR(FcFontList
);
1801 LOAD_FUNCPTR(FcFontSetDestroy
);
1802 LOAD_FUNCPTR(FcInit
);
1803 LOAD_FUNCPTR(FcObjectSetAdd
);
1804 LOAD_FUNCPTR(FcObjectSetCreate
);
1805 LOAD_FUNCPTR(FcObjectSetDestroy
);
1806 LOAD_FUNCPTR(FcPatternCreate
);
1807 LOAD_FUNCPTR(FcPatternDestroy
);
1808 LOAD_FUNCPTR(FcPatternGetBool
);
1809 LOAD_FUNCPTR(FcPatternGetString
);
1812 if(!pFcInit()) return;
1814 config
= pFcConfigGetCurrent();
1815 pat
= pFcPatternCreate();
1816 os
= pFcObjectSetCreate();
1817 pFcObjectSetAdd(os
, FC_FILE
);
1818 pFcObjectSetAdd(os
, FC_SCALABLE
);
1819 fontset
= pFcFontList(config
, pat
, os
);
1820 if(!fontset
) return;
1821 for(i
= 0; i
< fontset
->nfont
; i
++) {
1824 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1826 TRACE("fontconfig: %s\n", file
);
1828 /* We're just interested in OT/TT fonts for now, so this hack just
1829 picks up the scalable fonts without extensions .pf[ab] to save time
1830 loading every other font */
1832 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1834 TRACE("not scalable\n");
1838 len
= strlen( file
);
1839 if(len
< 4) continue;
1840 ext
= &file
[ len
- 3 ];
1841 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1842 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1844 pFcFontSetDestroy(fontset
);
1845 pFcObjectSetDestroy(os
);
1846 pFcPatternDestroy(pat
);
1852 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1855 const char *data_dir
= wine_get_data_dir();
1857 if (!data_dir
) data_dir
= wine_get_build_dir();
1864 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1866 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1868 strcpy(unix_name
, data_dir
);
1869 strcat(unix_name
, "/fonts/");
1871 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1873 EnterCriticalSection( &freetype_cs
);
1874 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1875 LeaveCriticalSection( &freetype_cs
);
1876 HeapFree(GetProcessHeap(), 0, unix_name
);
1881 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1883 static const WCHAR slashW
[] = {'\\','\0'};
1885 WCHAR windowsdir
[MAX_PATH
];
1888 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1889 strcatW(windowsdir
, fontsW
);
1890 strcatW(windowsdir
, slashW
);
1891 strcatW(windowsdir
, file
);
1892 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1893 EnterCriticalSection( &freetype_cs
);
1894 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1895 LeaveCriticalSection( &freetype_cs
);
1896 HeapFree(GetProcessHeap(), 0, unixname
);
1901 static void load_system_fonts(void)
1904 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1905 const WCHAR
* const *value
;
1907 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1910 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1911 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1912 strcatW(windowsdir
, fontsW
);
1913 for(value
= SystemFontValues
; *value
; value
++) {
1914 dlen
= sizeof(data
);
1915 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1919 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1920 if((unixname
= wine_get_unix_file_name(pathW
))) {
1921 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1922 HeapFree(GetProcessHeap(), 0, unixname
);
1925 load_font_from_data_dir(data
);
1932 /*************************************************************
1934 * This adds registry entries for any externally loaded fonts
1935 * (fonts from fontconfig or FontDirs). It also deletes entries
1936 * of no longer existing fonts.
1939 static void update_reg_entries(void)
1941 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1946 struct list
*family_elem_ptr
, *face_elem_ptr
;
1948 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1949 static const WCHAR spaceW
[] = {' ', '\0'};
1952 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1953 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1954 ERR("Can't create Windows font reg key\n");
1958 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1959 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1960 ERR("Can't create Windows font reg key\n");
1964 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1965 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1966 ERR("Can't create external font reg key\n");
1970 /* enumerate the fonts and add external ones to the two keys */
1972 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1973 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1974 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1975 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1976 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1977 if(!face
->external
) continue;
1979 if (!(face
->ntmFlags
& NTM_REGULAR
))
1980 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1981 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1982 strcpyW(valueW
, family
->FamilyName
);
1983 if(len
!= len_fam
) {
1984 strcatW(valueW
, spaceW
);
1985 strcatW(valueW
, face
->StyleName
);
1987 strcatW(valueW
, TrueType
);
1989 file
= wine_get_dos_file_name(face
->file
);
1991 len
= strlenW(file
) + 1;
1994 if((path
= strrchr(face
->file
, '/')) == NULL
)
1998 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2000 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2001 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2003 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2004 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2005 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2007 HeapFree(GetProcessHeap(), 0, file
);
2008 HeapFree(GetProcessHeap(), 0, valueW
);
2012 if(external_key
) RegCloseKey(external_key
);
2013 if(win9x_key
) RegCloseKey(win9x_key
);
2014 if(winnt_key
) RegCloseKey(winnt_key
);
2018 static void delete_external_font_keys(void)
2020 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2021 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2025 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2026 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2027 ERR("Can't create Windows font reg key\n");
2031 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2032 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2033 ERR("Can't create Windows font reg key\n");
2037 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2038 ERR("Can't create external font reg key\n");
2042 /* Delete all external fonts added last time */
2044 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2045 &valuelen
, &datalen
, NULL
, NULL
);
2046 valuelen
++; /* returned value doesn't include room for '\0' */
2047 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2048 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2050 dlen
= datalen
* sizeof(WCHAR
);
2053 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2054 &dlen
) == ERROR_SUCCESS
) {
2056 RegDeleteValueW(winnt_key
, valueW
);
2057 RegDeleteValueW(win9x_key
, valueW
);
2058 /* reset dlen and vlen */
2062 HeapFree(GetProcessHeap(), 0, data
);
2063 HeapFree(GetProcessHeap(), 0, valueW
);
2065 /* Delete the old external fonts key */
2066 RegCloseKey(external_key
);
2067 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2070 if(win9x_key
) RegCloseKey(win9x_key
);
2071 if(winnt_key
) RegCloseKey(winnt_key
);
2074 /*************************************************************
2075 * WineEngAddFontResourceEx
2078 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2081 if (ft_handle
) /* do it only if we have freetype up and running */
2086 FIXME("Ignoring flags %x\n", flags
);
2088 if((unixname
= wine_get_unix_file_name(file
)))
2090 EnterCriticalSection( &freetype_cs
);
2091 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2092 LeaveCriticalSection( &freetype_cs
);
2093 HeapFree(GetProcessHeap(), 0, unixname
);
2095 if (!ret
&& !strchrW(file
, '\\')) {
2096 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2097 ret
= load_font_from_winfonts_dir(file
);
2099 /* Try in datadir/fonts (or builddir/fonts),
2100 * needed for Magic the Gathering Online
2102 ret
= load_font_from_data_dir(file
);
2109 /*************************************************************
2110 * WineEngAddFontMemResourceEx
2113 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2115 if (ft_handle
) /* do it only if we have freetype up and running */
2117 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2119 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2120 memcpy(pFontCopy
, pbFont
, cbFont
);
2122 EnterCriticalSection( &freetype_cs
);
2123 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2124 LeaveCriticalSection( &freetype_cs
);
2128 TRACE("AddFontToList failed\n");
2129 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2132 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2133 * For now return something unique but quite random
2135 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2136 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2143 /*************************************************************
2144 * WineEngRemoveFontResourceEx
2147 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2153 static const struct nls_update_font_list
2155 UINT ansi_cp
, oem_cp
;
2156 const char *oem
, *fixed
, *system
;
2157 const char *courier
, *serif
, *small
, *sserif
;
2158 /* these are for font substitutes */
2159 const char *shelldlg
, *tmsrmn
;
2160 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2164 const char *from
, *to
;
2165 } arial_0
, courier_new_0
, times_new_roman_0
;
2166 } nls_update_font_list
[] =
2168 /* Latin 1 (United States) */
2169 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2170 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2171 "Tahoma","Times New Roman",
2172 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2175 /* Latin 1 (Multilingual) */
2176 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2177 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2178 "Tahoma","Times New Roman", /* FIXME unverified */
2179 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2182 /* Eastern Europe */
2183 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2184 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2185 "Tahoma","Times New Roman", /* FIXME unverified */
2186 "Fixedsys,238", "System,238",
2187 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2188 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2189 { "Arial CE,0", "Arial,238" },
2190 { "Courier New CE,0", "Courier New,238" },
2191 { "Times New Roman CE,0", "Times New Roman,238" }
2194 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2195 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2196 "Tahoma","Times New Roman", /* FIXME unverified */
2197 "Fixedsys,204", "System,204",
2198 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2199 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2200 { "Arial Cyr,0", "Arial,204" },
2201 { "Courier New Cyr,0", "Courier New,204" },
2202 { "Times New Roman Cyr,0", "Times New Roman,204" }
2205 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2206 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2207 "Tahoma","Times New Roman", /* FIXME unverified */
2208 "Fixedsys,161", "System,161",
2209 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2210 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2211 { "Arial Greek,0", "Arial,161" },
2212 { "Courier New Greek,0", "Courier New,161" },
2213 { "Times New Roman Greek,0", "Times New Roman,161" }
2216 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2217 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2218 "Tahoma","Times New Roman", /* FIXME unverified */
2219 "Fixedsys,162", "System,162",
2220 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2221 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2222 { "Arial Tur,0", "Arial,162" },
2223 { "Courier New Tur,0", "Courier New,162" },
2224 { "Times New Roman Tur,0", "Times New Roman,162" }
2227 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2228 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2229 "Tahoma","Times New Roman", /* FIXME unverified */
2230 "Fixedsys,177", "System,177",
2231 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2232 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2236 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2237 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2238 "Tahoma","Times New Roman", /* FIXME unverified */
2239 "Fixedsys,178", "System,178",
2240 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2241 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2245 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2246 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2247 "Tahoma","Times New Roman", /* FIXME unverified */
2248 "Fixedsys,186", "System,186",
2249 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2250 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2251 { "Arial Baltic,0", "Arial,186" },
2252 { "Courier New Baltic,0", "Courier New,186" },
2253 { "Times New Roman Baltic,0", "Times New Roman,186" }
2256 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2257 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2258 "Tahoma","Times New Roman", /* FIXME unverified */
2259 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2263 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2264 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2265 "Tahoma","Times New Roman", /* FIXME unverified */
2266 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2270 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2271 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2272 "MS UI Gothic","MS Serif",
2273 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2276 /* Chinese Simplified */
2277 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2278 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2279 "Tahoma", "Times New Roman", /* FIXME unverified */
2280 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2284 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2285 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2287 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2290 /* Chinese Traditional */
2291 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2292 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2293 "PMingLiU", "MingLiU",
2294 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2299 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2301 return ( ansi_cp
== 932 /* CP932 for Japanese */
2302 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2303 || ansi_cp
== 949 /* CP949 for Korean */
2304 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2307 static inline HKEY
create_fonts_NT_registry_key(void)
2311 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2312 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2316 static inline HKEY
create_fonts_9x_registry_key(void)
2320 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2321 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2325 static inline HKEY
create_config_fonts_registry_key(void)
2329 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2330 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2334 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2336 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2337 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2338 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2339 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2342 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2345 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2347 RegDeleteValueA(hkey
, name
);
2350 static void update_font_info(void)
2352 char buf
[40], cpbuf
[40];
2355 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2358 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2361 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2362 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2363 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2364 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2365 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2367 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2368 if (is_dbcs_ansi_cp(ansi_cp
))
2369 use_default_fallback
= TRUE
;
2372 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2374 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2379 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2381 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2383 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2386 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2390 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2391 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2393 hkey
= create_config_fonts_registry_key();
2394 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2395 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2396 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2399 hkey
= create_fonts_NT_registry_key();
2400 add_font_list(hkey
, &nls_update_font_list
[i
]);
2403 hkey
= create_fonts_9x_registry_key();
2404 add_font_list(hkey
, &nls_update_font_list
[i
]);
2407 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2409 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2410 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2411 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2412 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2414 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2415 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2416 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2417 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2418 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2419 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2420 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2421 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2423 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2424 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2425 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2433 /* Delete the FontSubstitutes from other locales */
2434 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2436 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2437 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2438 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2444 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2448 static BOOL
init_freetype(void)
2450 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2453 "Wine cannot find the FreeType font library. To enable Wine to\n"
2454 "use TrueType fonts please install a version of FreeType greater than\n"
2455 "or equal to 2.0.5.\n"
2456 "http://www.freetype.org\n");
2460 #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;}
2462 LOAD_FUNCPTR(FT_Vector_Unit
)
2463 LOAD_FUNCPTR(FT_Done_Face
)
2464 LOAD_FUNCPTR(FT_Get_Char_Index
)
2465 LOAD_FUNCPTR(FT_Get_Module
)
2466 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2467 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2468 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2469 LOAD_FUNCPTR(FT_Init_FreeType
)
2470 LOAD_FUNCPTR(FT_Load_Glyph
)
2471 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2472 #ifndef FT_MULFIX_INLINED
2473 LOAD_FUNCPTR(FT_MulFix
)
2475 LOAD_FUNCPTR(FT_New_Face
)
2476 LOAD_FUNCPTR(FT_New_Memory_Face
)
2477 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2478 LOAD_FUNCPTR(FT_Outline_Transform
)
2479 LOAD_FUNCPTR(FT_Outline_Translate
)
2480 LOAD_FUNCPTR(FT_Select_Charmap
)
2481 LOAD_FUNCPTR(FT_Set_Charmap
)
2482 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2483 LOAD_FUNCPTR(FT_Vector_Transform
)
2486 /* Don't warn if these ones are missing */
2487 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2488 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2489 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2490 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2491 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2492 #ifdef HAVE_FREETYPE_FTWINFNT_H
2493 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2495 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2496 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2497 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2498 <= 2.0.3 has FT_Sqrt64 */
2502 if(pFT_Init_FreeType(&library
) != 0) {
2503 ERR("Can't init FreeType library\n");
2504 wine_dlclose(ft_handle
, NULL
, 0);
2508 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2509 if (pFT_Library_Version
)
2510 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2512 if (FT_Version
.major
<=0)
2518 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2519 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2520 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2521 ((FT_Version
.patch
) & 0x0000ff);
2527 "Wine cannot find certain functions that it needs inside the FreeType\n"
2528 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2529 "FreeType to at least version 2.0.5.\n"
2530 "http://www.freetype.org\n");
2531 wine_dlclose(ft_handle
, NULL
, 0);
2536 /*************************************************************
2539 * Initialize FreeType library and create a list of available faces
2541 BOOL
WineEngInit(void)
2543 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2544 static const WCHAR pathW
[] = {'P','a','t','h',0};
2546 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2548 WCHAR windowsdir
[MAX_PATH
];
2551 const char *data_dir
;
2555 /* update locale dependent font info in registry */
2558 if(!init_freetype()) return FALSE
;
2560 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2561 ERR("Failed to create font mutex\n");
2564 WaitForSingleObject(font_mutex
, INFINITE
);
2566 delete_external_font_keys();
2568 /* load the system bitmap fonts */
2569 load_system_fonts();
2571 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2572 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2573 strcatW(windowsdir
, fontsW
);
2574 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2576 ReadFontDir(unixname
, FALSE
);
2577 HeapFree(GetProcessHeap(), 0, unixname
);
2580 /* load the system truetype fonts */
2581 data_dir
= wine_get_data_dir();
2582 if (!data_dir
) data_dir
= wine_get_build_dir();
2583 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2584 strcpy(unixname
, data_dir
);
2585 strcat(unixname
, "/fonts/");
2586 ReadFontDir(unixname
, TRUE
);
2587 HeapFree(GetProcessHeap(), 0, unixname
);
2590 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2591 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2592 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2594 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2595 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2596 &hkey
) == ERROR_SUCCESS
) {
2598 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2599 &valuelen
, &datalen
, NULL
, NULL
);
2601 valuelen
++; /* returned value doesn't include room for '\0' */
2602 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2603 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2606 dlen
= datalen
* sizeof(WCHAR
);
2608 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2609 &dlen
) == ERROR_SUCCESS
) {
2610 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2612 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2614 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2615 HeapFree(GetProcessHeap(), 0, unixname
);
2618 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2620 WCHAR pathW
[MAX_PATH
];
2621 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2624 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2625 if((unixname
= wine_get_unix_file_name(pathW
)))
2627 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2628 HeapFree(GetProcessHeap(), 0, unixname
);
2631 load_font_from_data_dir(data
);
2633 /* reset dlen and vlen */
2638 HeapFree(GetProcessHeap(), 0, data
);
2639 HeapFree(GetProcessHeap(), 0, valueW
);
2643 load_fontconfig_fonts();
2645 /* then look in any directories that we've specified in the config file */
2646 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2647 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2653 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2655 len
+= sizeof(WCHAR
);
2656 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2657 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2659 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2660 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2661 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2662 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2666 LPSTR next
= strchr( ptr
, ':' );
2667 if (next
) *next
++ = 0;
2668 ReadFontDir( ptr
, TRUE
);
2671 HeapFree( GetProcessHeap(), 0, valueA
);
2673 HeapFree( GetProcessHeap(), 0, valueW
);
2682 update_reg_entries();
2684 init_system_links();
2686 ReleaseMutex(font_mutex
);
2691 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2694 TT_HoriHeader
*pHori
;
2698 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2699 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2701 if(height
== 0) height
= 16;
2703 /* Calc. height of EM square:
2705 * For +ve lfHeight we have
2706 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2707 * Re-arranging gives:
2708 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2710 * For -ve lfHeight we have
2712 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2713 * with il = winAscent + winDescent - units_per_em]
2718 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2719 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2720 pHori
->Ascender
- pHori
->Descender
);
2722 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2723 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2731 static struct font_mapping
*map_font_file( const char *name
)
2733 struct font_mapping
*mapping
;
2737 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2738 if (fstat( fd
, &st
) == -1) goto error
;
2740 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2742 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2744 mapping
->refcount
++;
2749 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2752 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2755 if (mapping
->data
== MAP_FAILED
)
2757 HeapFree( GetProcessHeap(), 0, mapping
);
2760 mapping
->refcount
= 1;
2761 mapping
->dev
= st
.st_dev
;
2762 mapping
->ino
= st
.st_ino
;
2763 mapping
->size
= st
.st_size
;
2764 list_add_tail( &mappings_list
, &mapping
->entry
);
2772 static void unmap_font_file( struct font_mapping
*mapping
)
2774 if (!--mapping
->refcount
)
2776 list_remove( &mapping
->entry
);
2777 munmap( mapping
->data
, mapping
->size
);
2778 HeapFree( GetProcessHeap(), 0, mapping
);
2782 static LONG
load_VDMX(GdiFont
*, LONG
);
2784 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2791 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2795 if (!(font
->mapping
= map_font_file( face
->file
)))
2797 WARN("failed to map %s\n", debugstr_a(face
->file
));
2800 data_ptr
= font
->mapping
->data
;
2801 data_size
= font
->mapping
->size
;
2805 data_ptr
= face
->font_data_ptr
;
2806 data_size
= face
->font_data_size
;
2809 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
2811 ERR("FT_New_Face rets %d\n", err
);
2815 /* set it here, as load_VDMX needs it */
2816 font
->ft_face
= ft_face
;
2818 if(FT_IS_SCALABLE(ft_face
)) {
2819 /* load the VDMX table if we have one */
2820 font
->ppem
= load_VDMX(font
, height
);
2822 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2823 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
2825 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2826 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2828 font
->ppem
= height
;
2829 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2830 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2836 static int get_nearest_charset(Face
*face
, int *cp
)
2838 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2839 a single face with the requested charset. The idea is to check if
2840 the selected font supports the current ANSI codepage, if it does
2841 return the corresponding charset, else return the first charset */
2844 int acp
= GetACP(), i
;
2848 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2849 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2850 return csi
.ciCharset
;
2852 for(i
= 0; i
< 32; i
++) {
2854 if(face
->fs
.fsCsb
[0] & fs0
) {
2855 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2857 return csi
.ciCharset
;
2860 FIXME("TCI failing on %x\n", fs0
);
2864 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2865 face
->fs
.fsCsb
[0], face
->file
);
2867 return DEFAULT_CHARSET
;
2870 static GdiFont
*alloc_font(void)
2872 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2874 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2875 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2877 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2878 ret
->total_kern_pairs
= (DWORD
)-1;
2879 ret
->kern_pairs
= NULL
;
2880 list_init(&ret
->hfontlist
);
2881 list_init(&ret
->child_fonts
);
2885 static void free_font(GdiFont
*font
)
2887 struct list
*cursor
, *cursor2
;
2890 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2892 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2893 struct list
*first_hfont
;
2894 HFONTLIST
*hfontlist
;
2895 list_remove(cursor
);
2898 first_hfont
= list_head(&child
->font
->hfontlist
);
2899 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2900 DeleteObject(hfontlist
->hfont
);
2901 HeapFree(GetProcessHeap(), 0, hfontlist
);
2902 free_font(child
->font
);
2904 HeapFree(GetProcessHeap(), 0, child
);
2907 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2908 if (font
->mapping
) unmap_font_file( font
->mapping
);
2909 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2910 HeapFree(GetProcessHeap(), 0, font
->potm
);
2911 HeapFree(GetProcessHeap(), 0, font
->name
);
2912 for (i
= 0; i
< font
->gmsize
; i
++)
2913 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2914 HeapFree(GetProcessHeap(), 0, font
->gm
);
2915 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
2916 HeapFree(GetProcessHeap(), 0, font
);
2920 /*************************************************************
2923 * load the vdmx entry for the specified height
2926 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2927 ( ( (FT_ULong)_x4 << 24 ) | \
2928 ( (FT_ULong)_x3 << 16 ) | \
2929 ( (FT_ULong)_x2 << 8 ) | \
2932 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2947 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2951 BYTE devXRatio
, devYRatio
;
2952 USHORT numRecs
, numRatios
;
2953 DWORD result
, offset
= -1;
2957 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2959 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2962 /* FIXME: need the real device aspect ratio */
2966 numRecs
= GET_BE_WORD(hdr
[1]);
2967 numRatios
= GET_BE_WORD(hdr
[2]);
2969 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2970 for(i
= 0; i
< numRatios
; i
++) {
2973 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2974 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2977 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2979 if((ratio
.xRatio
== 0 &&
2980 ratio
.yStartRatio
== 0 &&
2981 ratio
.yEndRatio
== 0) ||
2982 (devXRatio
== ratio
.xRatio
&&
2983 devYRatio
>= ratio
.yStartRatio
&&
2984 devYRatio
<= ratio
.yEndRatio
))
2986 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2987 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2988 offset
= GET_BE_WORD(tmp
);
2994 FIXME("No suitable ratio found\n");
2998 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3000 BYTE startsz
, endsz
;
3003 recs
= GET_BE_WORD(group
.recs
);
3004 startsz
= group
.startsz
;
3005 endsz
= group
.endsz
;
3007 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3009 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3010 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3011 if(result
== GDI_ERROR
) {
3012 FIXME("Failed to retrieve vTable\n");
3017 for(i
= 0; i
< recs
; i
++) {
3018 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3019 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3020 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3022 if(yMax
+ -yMin
== height
) {
3025 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3028 if(yMax
+ -yMin
> height
) {
3031 goto end
; /* failed */
3033 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3034 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3035 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3036 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3042 TRACE("ppem not found for height %d\n", height
);
3046 if(ppem
< startsz
|| ppem
> endsz
)
3049 for(i
= 0; i
< recs
; i
++) {
3051 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
3053 if(yPelHeight
> ppem
)
3056 if(yPelHeight
== ppem
) {
3057 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3058 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3059 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
3065 HeapFree(GetProcessHeap(), 0, vTable
);
3071 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3073 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3074 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3075 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3076 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3077 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3080 static void calc_hash(FONT_DESC
*pfd
)
3082 DWORD hash
= 0, *ptr
, two_chars
;
3086 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3088 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3090 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3092 pwc
= (WCHAR
*)&two_chars
;
3094 *pwc
= toupperW(*pwc
);
3096 *pwc
= toupperW(*pwc
);
3100 hash
^= !pfd
->can_use_bitmap
;
3105 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3110 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3114 fd
.can_use_bitmap
= can_use_bitmap
;
3117 /* try the child list */
3118 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3119 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3120 if(!fontcmp(ret
, &fd
)) {
3121 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3122 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3123 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3124 if(hflist
->hfont
== hfont
)
3130 /* try the in-use list */
3131 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3132 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3133 if(!fontcmp(ret
, &fd
)) {
3134 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3135 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3136 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3137 if(hflist
->hfont
== hfont
)
3140 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3141 hflist
->hfont
= hfont
;
3142 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3147 /* then the unused list */
3148 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3149 while(font_elem_ptr
) {
3150 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3151 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3152 if(!fontcmp(ret
, &fd
)) {
3153 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3154 assert(list_empty(&ret
->hfontlist
));
3155 TRACE("Found %p in unused list\n", ret
);
3156 list_remove(&ret
->entry
);
3157 list_add_head(&gdi_font_list
, &ret
->entry
);
3158 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3159 hflist
->hfont
= hfont
;
3160 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3167 static void add_to_cache(GdiFont
*font
)
3169 static DWORD cache_num
= 1;
3171 font
->cache_num
= cache_num
++;
3172 list_add_head(&gdi_font_list
, &font
->entry
);
3175 /*************************************************************
3176 * create_child_font_list
3178 static BOOL
create_child_font_list(GdiFont
*font
)
3181 SYSTEM_LINKS
*font_link
;
3182 CHILD_FONT
*font_link_entry
, *new_child
;
3184 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3186 if(!strcmpW(font_link
->font_name
, font
->name
))
3188 TRACE("found entry in system list\n");
3189 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3191 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3192 new_child
->face
= font_link_entry
->face
;
3193 new_child
->font
= NULL
;
3194 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3195 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3202 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3203 * Sans Serif. This is how asian windows get default fallbacks for fonts
3205 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3206 font
->charset
!= OEM_CHARSET
&&
3207 strcmpW(font
->name
,szDefaultFallbackLink
) != 0)
3208 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3210 if(!strcmpW(font_link
->font_name
,szDefaultFallbackLink
))
3212 TRACE("found entry in default fallback 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
);
3229 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3231 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3233 if (pFT_Set_Charmap
)
3236 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3238 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3240 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3242 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3244 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3245 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3247 switch (ft_face
->charmaps
[i
]->platform_id
)
3250 cmap_def
= ft_face
->charmaps
[i
];
3252 case 0: /* Apple Unicode */
3253 cmap0
= ft_face
->charmaps
[i
];
3255 case 1: /* Macintosh */
3256 cmap1
= ft_face
->charmaps
[i
];
3259 cmap2
= ft_face
->charmaps
[i
];
3261 case 3: /* Microsoft */
3262 cmap3
= ft_face
->charmaps
[i
];
3267 if (cmap3
) /* prefer Microsoft cmap table */
3268 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3270 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3272 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3274 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3276 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3278 return ft_err
== FT_Err_Ok
;
3281 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3284 /*************************************************************
3285 * WineEngCreateFontInstance
3288 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3291 Face
*face
, *best
, *best_bitmap
;
3292 Family
*family
, *last_resort_family
;
3293 struct list
*family_elem_ptr
, *face_elem_ptr
;
3294 INT height
, width
= 0;
3295 unsigned int score
= 0, new_score
;
3296 signed int diff
= 0, newdiff
;
3297 BOOL bd
, it
, can_use_bitmap
;
3302 FontSubst
*psub
= NULL
;
3304 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3305 lf
.lfWidth
= abs(lf
.lfWidth
);
3307 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3309 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3310 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3311 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3314 if(dc
->GraphicsMode
== GM_ADVANCED
)
3315 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3318 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3319 font scaling abilities. */
3320 dcmat
.eM11
= dcmat
.eM22
= fabs(dc
->xformWorld2Vport
.eM22
);
3321 dcmat
.eM21
= dcmat
.eM12
= 0;
3324 /* Try to avoid not necessary glyph transformations */
3325 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3327 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3328 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3329 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3332 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3333 dcmat
.eM21
, dcmat
.eM22
);
3335 EnterCriticalSection( &freetype_cs
);
3337 /* check the cache first */
3338 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3339 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3340 LeaveCriticalSection( &freetype_cs
);
3344 TRACE("not in cache\n");
3345 if(list_empty(&font_list
)) /* No fonts installed */
3347 TRACE("No fonts installed\n");
3348 LeaveCriticalSection( &freetype_cs
);
3351 if(!have_installed_roman_font
)
3353 TRACE("No roman font installed\n");
3354 LeaveCriticalSection( &freetype_cs
);
3360 ret
->font_desc
.matrix
= dcmat
;
3361 ret
->font_desc
.lf
= lf
;
3362 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3363 calc_hash(&ret
->font_desc
);
3364 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3365 hflist
->hfont
= hfont
;
3366 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3368 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3369 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3370 original value lfCharSet. Note this is a special case for
3371 Symbol and doesn't happen at least for "Wingdings*" */
3373 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3374 lf
.lfCharSet
= SYMBOL_CHARSET
;
3376 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3377 switch(lf
.lfCharSet
) {
3378 case DEFAULT_CHARSET
:
3379 csi
.fs
.fsCsb
[0] = 0;
3382 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3383 csi
.fs
.fsCsb
[0] = 0;
3389 if(lf
.lfFaceName
[0] != '\0') {
3390 SYSTEM_LINKS
*font_link
;
3391 CHILD_FONT
*font_link_entry
;
3392 LPWSTR FaceName
= lf
.lfFaceName
;
3395 * Check for a leading '@' this signals that the font is being
3396 * requested in tategaki mode (vertical writing substitution) but
3397 * does not affect the fontface that is to be selected.
3399 if (lf
.lfFaceName
[0]=='@')
3400 FaceName
= &lf
.lfFaceName
[1];
3402 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3405 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3406 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3407 if (psub
->to
.charset
!= -1)
3408 lf
.lfCharSet
= psub
->to
.charset
;
3411 /* We want a match on name and charset or just name if
3412 charset was DEFAULT_CHARSET. If the latter then
3413 we fixup the returned charset later in get_nearest_charset
3414 where we'll either use the charset of the current ansi codepage
3415 or if that's unavailable the first charset that the font supports.
3417 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3418 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3419 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3420 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3422 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3423 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3424 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3425 if(face
->scalable
|| can_use_bitmap
)
3432 * Try check the SystemLink list first for a replacement font.
3433 * We may find good replacements there.
3435 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3437 if(!strcmpiW(font_link
->font_name
, FaceName
))
3439 TRACE("found entry in system list\n");
3440 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3442 face
= font_link_entry
->face
;
3443 family
= face
->family
;
3444 if(csi
.fs
.fsCsb
[0] &
3445 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3447 if(face
->scalable
|| can_use_bitmap
)
3455 psub
= NULL
; /* substitution is no more relevant */
3457 /* If requested charset was DEFAULT_CHARSET then try using charset
3458 corresponding to the current ansi codepage */
3459 if (!csi
.fs
.fsCsb
[0])
3462 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3463 FIXME("TCI failed on codepage %d\n", acp
);
3464 csi
.fs
.fsCsb
[0] = 0;
3466 lf
.lfCharSet
= csi
.ciCharset
;
3469 /* Face families are in the top 4 bits of lfPitchAndFamily,
3470 so mask with 0xF0 before testing */
3472 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3473 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3474 strcpyW(lf
.lfFaceName
, defFixed
);
3475 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3476 strcpyW(lf
.lfFaceName
, defSerif
);
3477 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3478 strcpyW(lf
.lfFaceName
, defSans
);
3480 strcpyW(lf
.lfFaceName
, defSans
);
3481 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3482 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3483 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3484 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3485 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3486 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3487 if(face
->scalable
|| can_use_bitmap
)
3493 last_resort_family
= NULL
;
3494 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3495 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3496 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3497 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3498 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3501 if(can_use_bitmap
&& !last_resort_family
)
3502 last_resort_family
= family
;
3507 if(last_resort_family
) {
3508 family
= last_resort_family
;
3509 csi
.fs
.fsCsb
[0] = 0;
3513 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3514 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3515 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3516 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3517 if(face
->scalable
) {
3518 csi
.fs
.fsCsb
[0] = 0;
3519 WARN("just using first face for now\n");
3522 if(can_use_bitmap
&& !last_resort_family
)
3523 last_resort_family
= family
;
3526 if(!last_resort_family
) {
3527 FIXME("can't find a single appropriate font - bailing\n");
3529 LeaveCriticalSection( &freetype_cs
);
3533 WARN("could only find a bitmap font - this will probably look awful!\n");
3534 family
= last_resort_family
;
3535 csi
.fs
.fsCsb
[0] = 0;
3538 it
= lf
.lfItalic
? 1 : 0;
3539 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3541 height
= lf
.lfHeight
;
3543 face
= best
= best_bitmap
= NULL
;
3544 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3546 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3550 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3551 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3552 new_score
= (italic
^ it
) + (bold
^ bd
);
3553 if(!best
|| new_score
<= score
)
3555 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3556 italic
, bold
, it
, bd
);
3559 if(best
->scalable
&& score
== 0) break;
3563 newdiff
= height
- (signed int)(best
->size
.height
);
3565 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3566 if(!best_bitmap
|| new_score
< score
||
3567 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3569 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3572 if(score
== 0 && diff
== 0) break;
3579 face
= best
->scalable
? best
: best_bitmap
;
3580 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3581 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3585 if(csi
.fs
.fsCsb
[0]) {
3586 ret
->charset
= lf
.lfCharSet
;
3587 ret
->codepage
= csi
.ciACP
;
3590 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3592 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3593 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3595 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3597 if(!face
->scalable
) {
3598 /* Windows uses integer scaling factors for bitmap fonts */
3599 INT scale
, scaled_height
;
3601 /* FIXME: rotation of bitmap fonts is ignored */
3602 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3604 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3605 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3607 if (height
!= 0) height
= diff
;
3608 height
+= face
->size
.height
;
3610 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3611 scaled_height
= scale
* face
->size
.height
;
3612 /* XP allows not more than 10% deviation */
3613 if (scale
> 1 && scaled_height
- height
> scaled_height
/ 10) scale
--;
3614 ret
->scale_y
= scale
;
3616 width
= face
->size
.x_ppem
>> 6;
3617 height
= face
->size
.y_ppem
>> 6;
3621 TRACE("font scale y: %f\n", ret
->scale_y
);
3623 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3628 LeaveCriticalSection( &freetype_cs
);
3632 ret
->ntmFlags
= face
->ntmFlags
;
3634 if (ret
->charset
== SYMBOL_CHARSET
&&
3635 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3638 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3642 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3645 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3646 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3647 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3648 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3649 create_child_font_list(ret
);
3651 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3653 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3654 if (length
!= GDI_ERROR
)
3656 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3657 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3658 TRACE("Loaded GSUB table of %i bytes\n",length
);
3662 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3665 LeaveCriticalSection( &freetype_cs
);
3669 static void dump_gdi_font_list(void)
3672 struct list
*elem_ptr
;
3674 TRACE("---------- gdiFont Cache ----------\n");
3675 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3676 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3677 TRACE("gdiFont=%p %s %d\n",
3678 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3681 TRACE("---------- Unused gdiFont Cache ----------\n");
3682 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3683 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3684 TRACE("gdiFont=%p %s %d\n",
3685 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3689 /*************************************************************
3690 * WineEngDestroyFontInstance
3692 * free the gdiFont associated with this handle
3695 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3700 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3703 EnterCriticalSection( &freetype_cs
);
3705 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3707 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3708 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3709 if(hflist
->hfont
== handle
)
3711 TRACE("removing child font %p from child list\n", gdiFont
);
3712 list_remove(&gdiFont
->entry
);
3713 LeaveCriticalSection( &freetype_cs
);
3718 TRACE("destroying hfont=%p\n", handle
);
3720 dump_gdi_font_list();
3722 font_elem_ptr
= list_head(&gdi_font_list
);
3723 while(font_elem_ptr
) {
3724 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3725 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3727 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3728 while(hfontlist_elem_ptr
) {
3729 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3730 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3731 if(hflist
->hfont
== handle
) {
3732 list_remove(&hflist
->entry
);
3733 HeapFree(GetProcessHeap(), 0, hflist
);
3737 if(list_empty(&gdiFont
->hfontlist
)) {
3738 TRACE("Moving to Unused list\n");
3739 list_remove(&gdiFont
->entry
);
3740 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3745 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3746 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3747 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3748 while(font_elem_ptr
) {
3749 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3750 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3751 TRACE("freeing %p\n", gdiFont
);
3752 list_remove(&gdiFont
->entry
);
3755 LeaveCriticalSection( &freetype_cs
);
3759 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3760 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3765 if (face
->cached_enum_data
)
3768 *pelf
= face
->cached_enum_data
->elf
;
3769 *pntm
= face
->cached_enum_data
->ntm
;
3770 *ptype
= face
->cached_enum_data
->type
;
3774 font
= alloc_font();
3776 if(face
->scalable
) {
3777 height
= -2048; /* 2048 is the most common em size */
3780 height
= face
->size
.y_ppem
>> 6;
3781 width
= face
->size
.x_ppem
>> 6;
3783 font
->scale_y
= 1.0;
3785 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3791 font
->name
= strdupW(face
->family
->FamilyName
);
3792 font
->ntmFlags
= face
->ntmFlags
;
3794 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3796 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
3798 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
3800 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3801 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
3803 lstrcpynW(pelf
->elfFullName
,
3804 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
3806 lstrcpynW(pelf
->elfStyle
,
3807 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
3812 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
3814 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3816 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3817 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
3818 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
3821 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
3822 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3823 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3824 pntm
->ntmFontSig
= face
->fs
;
3826 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3828 pelf
->elfLogFont
.lfEscapement
= 0;
3829 pelf
->elfLogFont
.lfOrientation
= 0;
3830 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
3831 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3832 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
3833 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
3834 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
3835 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
3836 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
3837 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3838 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3839 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3840 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
3843 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
3844 *ptype
|= TRUETYPE_FONTTYPE
;
3845 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
3846 *ptype
|= DEVICE_FONTTYPE
;
3847 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
3848 *ptype
|= RASTER_FONTTYPE
;
3850 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
3851 if (face
->cached_enum_data
)
3853 face
->cached_enum_data
->elf
= *pelf
;
3854 face
->cached_enum_data
->ntm
= *pntm
;
3855 face
->cached_enum_data
->type
= *ptype
;
3861 /*************************************************************
3865 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3869 struct list
*family_elem_ptr
, *face_elem_ptr
;
3871 NEWTEXTMETRICEXW ntm
;
3880 lf
.lfCharSet
= DEFAULT_CHARSET
;
3881 lf
.lfPitchAndFamily
= 0;
3882 lf
.lfFaceName
[0] = 0;
3886 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3888 EnterCriticalSection( &freetype_cs
);
3889 if(plf
->lfFaceName
[0]) {
3891 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3894 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3895 debugstr_w(psub
->to
.name
));
3897 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3901 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3902 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3903 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3904 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3905 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3906 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3907 for(i
= 0; i
< 32; i
++) {
3908 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3909 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3910 strcpyW(elf
.elfScript
, OEM_DOSW
);
3911 i
= 32; /* break out of loop */
3912 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3915 fs
.fsCsb
[0] = 1L << i
;
3917 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3919 csi
.ciCharset
= DEFAULT_CHARSET
;
3920 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3921 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3922 elf
.elfLogFont
.lfCharSet
=
3923 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3925 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3927 FIXME("Unknown elfscript for bit %d\n", i
);
3930 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3931 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3932 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3933 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3934 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3935 ntm
.ntmTm
.ntmFlags
);
3936 /* release section before callback (FIXME) */
3937 LeaveCriticalSection( &freetype_cs
);
3938 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3939 EnterCriticalSection( &freetype_cs
);
3945 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3946 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3947 face_elem_ptr
= list_head(&family
->faces
);
3948 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3949 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3950 for(i
= 0; i
< 32; i
++) {
3951 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3952 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3953 strcpyW(elf
.elfScript
, OEM_DOSW
);
3954 i
= 32; /* break out of loop */
3955 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3958 fs
.fsCsb
[0] = 1L << i
;
3960 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3962 csi
.ciCharset
= DEFAULT_CHARSET
;
3963 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3964 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3965 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3968 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3970 FIXME("Unknown elfscript for bit %d\n", i
);
3973 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3974 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3975 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3976 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3977 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3978 ntm
.ntmTm
.ntmFlags
);
3979 /* release section before callback (FIXME) */
3980 LeaveCriticalSection( &freetype_cs
);
3981 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
3982 EnterCriticalSection( &freetype_cs
);
3986 LeaveCriticalSection( &freetype_cs
);
3990 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3992 pt
->x
.value
= vec
->x
>> 6;
3993 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3994 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3995 pt
->y
.value
= vec
->y
>> 6;
3996 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3997 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4001 /***************************************************
4002 * According to the MSDN documentation on WideCharToMultiByte,
4003 * certain codepages cannot set the default_used parameter.
4004 * This returns TRUE if the codepage can set that parameter, false else
4005 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4007 static BOOL
codepage_sets_default_used(UINT codepage
)
4021 * GSUB Table handling functions
4024 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4026 const GSUB_CoverageFormat1
* cf1
;
4028 cf1
= (GSUB_CoverageFormat1
*)table
;
4030 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4032 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4034 TRACE("Coverage Format 1, %i glyphs\n",count
);
4035 for (i
= 0; i
< count
; i
++)
4036 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4040 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4042 const GSUB_CoverageFormat2
* cf2
;
4045 cf2
= (GSUB_CoverageFormat2
*)cf1
;
4047 count
= GET_BE_WORD(cf2
->RangeCount
);
4048 TRACE("Coverage Format 2, %i ranges\n",count
);
4049 for (i
= 0; i
< count
; i
++)
4051 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4053 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4054 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4056 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4057 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4063 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4068 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4070 const GSUB_ScriptList
*script
;
4071 const GSUB_Script
*deflt
= NULL
;
4073 script
= (GSUB_ScriptList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->ScriptList
));
4075 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4076 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4078 const GSUB_Script
*scr
;
4081 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4082 scr
= (GSUB_Script
*)((LPBYTE
)script
+ offset
);
4084 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4086 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4092 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4096 const GSUB_LangSys
*Lang
;
4098 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4100 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4102 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4103 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4105 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4108 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4111 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4117 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4120 const GSUB_FeatureList
*feature
;
4121 feature
= (GSUB_FeatureList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->FeatureList
));
4123 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4124 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4126 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4127 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4129 const GSUB_Feature
*feat
;
4130 feat
= (GSUB_Feature
*)((LPBYTE
)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4137 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4141 const GSUB_LookupList
*lookup
;
4142 lookup
= (GSUB_LookupList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->LookupList
));
4144 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4145 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4147 const GSUB_LookupTable
*look
;
4148 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4149 look
= (GSUB_LookupTable
*)((LPBYTE
)lookup
+ offset
);
4150 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4151 if (GET_BE_WORD(look
->LookupType
) != 1)
4152 FIXME("We only handle SubType 1\n");
4157 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4159 const GSUB_SingleSubstFormat1
*ssf1
;
4160 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4161 ssf1
= (GSUB_SingleSubstFormat1
*)((LPBYTE
)look
+offset
);
4162 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4164 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4165 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4166 if (GSUB_is_glyph_covered((LPBYTE
)ssf1
+offset
, glyph
) != -1)
4168 TRACE(" Glyph 0x%x ->",glyph
);
4169 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4170 TRACE(" 0x%x\n",glyph
);
4175 const GSUB_SingleSubstFormat2
*ssf2
;
4179 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
4180 offset
= GET_BE_WORD(ssf1
->Coverage
);
4181 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4182 index
= GSUB_is_glyph_covered((LPBYTE
)ssf2
+offset
, glyph
);
4183 TRACE(" Coverage index %i\n",index
);
4186 TRACE(" Glyph is 0x%x ->",glyph
);
4187 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4188 TRACE("0x%x\n",glyph
);
4197 static const char* get_opentype_script(const GdiFont
*font
)
4200 * I am not sure if this is the correct way to generate our script tag
4203 switch (font
->charset
)
4205 case ANSI_CHARSET
: return "latn";
4206 case BALTIC_CHARSET
: return "latn"; /* ?? */
4207 case CHINESEBIG5_CHARSET
: return "hani";
4208 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4209 case GB2312_CHARSET
: return "hani";
4210 case GREEK_CHARSET
: return "grek";
4211 case HANGUL_CHARSET
: return "hang";
4212 case RUSSIAN_CHARSET
: return "cyrl";
4213 case SHIFTJIS_CHARSET
: return "kana";
4214 case TURKISH_CHARSET
: return "latn"; /* ?? */
4215 case VIETNAMESE_CHARSET
: return "latn";
4216 case JOHAB_CHARSET
: return "latn"; /* ?? */
4217 case ARABIC_CHARSET
: return "arab";
4218 case HEBREW_CHARSET
: return "hebr";
4219 case THAI_CHARSET
: return "thai";
4220 default: return "latn";
4224 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4226 const GSUB_Header
*header
;
4227 const GSUB_Script
*script
;
4228 const GSUB_LangSys
*language
;
4229 const GSUB_Feature
*feature
;
4231 if (!font
->GSUB_Table
)
4234 header
= font
->GSUB_Table
;
4236 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4239 TRACE("Script not found\n");
4242 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4245 TRACE("Language not found\n");
4248 feature
= GSUB_get_feature(header
, language
, "vrt2");
4250 feature
= GSUB_get_feature(header
, language
, "vert");
4253 TRACE("vrt2/vert feature not found\n");
4256 return GSUB_apply_feature(header
, feature
, glyph
);
4259 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4263 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4264 WCHAR wc
= (WCHAR
)glyph
;
4266 BOOL
*default_used_pointer
;
4269 default_used_pointer
= NULL
;
4270 default_used
= FALSE
;
4271 if (codepage_sets_default_used(font
->codepage
))
4272 default_used_pointer
= &default_used
;
4273 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4276 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4277 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4278 return get_GSUB_vert_glyph(font
,ret
);
4281 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4282 glyph
= glyph
+ 0xf000;
4283 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4284 return get_GSUB_vert_glyph(font
,glyphId
);
4287 /*************************************************************
4288 * WineEngGetGlyphIndices
4291 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4292 LPWORD pgi
, DWORD flags
)
4295 int default_char
= -1;
4297 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4299 for(i
= 0; i
< count
; i
++)
4301 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4304 if (default_char
== -1)
4306 if (FT_IS_SFNT(font
->ft_face
))
4308 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4309 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4314 WineEngGetTextMetrics(font
, &textm
);
4315 default_char
= textm
.tmDefaultChar
;
4318 pgi
[i
] = default_char
;
4324 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4326 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4327 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4330 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4332 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4333 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4336 /*************************************************************
4337 * WineEngGetGlyphOutline
4339 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4340 * except that the first parameter is the HWINEENGFONT of the font in
4341 * question rather than an HDC.
4344 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4345 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4348 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4349 FT_Face ft_face
= incoming_font
->ft_face
;
4350 GdiFont
*font
= incoming_font
;
4351 FT_UInt glyph_index
;
4352 DWORD width
, height
, pitch
, needed
= 0;
4353 FT_Bitmap ft_bitmap
;
4355 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4357 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4358 double widthRatio
= 1.0;
4359 FT_Matrix transMat
= identityMat
;
4360 FT_Matrix transMatUnrotated
;
4361 BOOL needsTransform
= FALSE
;
4362 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4363 UINT original_index
;
4365 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4366 buflen
, buf
, lpmat
);
4368 TRACE("font transform %f %f %f %f\n",
4369 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4370 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4372 EnterCriticalSection( &freetype_cs
);
4374 if(format
& GGO_GLYPH_INDEX
) {
4375 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4376 original_index
= glyph
;
4377 format
&= ~GGO_GLYPH_INDEX
;
4379 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4380 ft_face
= font
->ft_face
;
4381 original_index
= glyph_index
;
4384 if(format
& GGO_UNHINTED
) {
4385 load_flags
|= FT_LOAD_NO_HINTING
;
4386 format
&= ~GGO_UNHINTED
;
4389 /* tategaki never appears to happen to lower glyph index */
4390 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4393 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4394 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4395 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4396 font
->gmsize
* sizeof(GM
*));
4398 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4399 FONT_GM(font
,original_index
)->init
&& (!lpmat
|| is_identity_MAT2(lpmat
)))
4401 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4402 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4403 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4404 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4405 LeaveCriticalSection( &freetype_cs
);
4406 return 1; /* FIXME */
4410 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4411 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4413 /* Scaling factor */
4418 WineEngGetTextMetrics(font
, &tm
);
4420 widthRatio
= (double)font
->aveWidth
;
4421 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4424 widthRatio
= font
->scale_y
;
4426 /* Scaling transform */
4427 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4430 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4433 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4435 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4436 needsTransform
= TRUE
;
4439 /* Slant transform */
4440 if (font
->fake_italic
) {
4443 slantMat
.xx
= (1 << 16);
4444 slantMat
.xy
= ((1 << 16) >> 2);
4446 slantMat
.yy
= (1 << 16);
4447 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4448 needsTransform
= TRUE
;
4451 /* Rotation transform */
4452 transMatUnrotated
= transMat
;
4453 if(font
->orientation
&& !tategaki
) {
4454 FT_Matrix rotationMat
;
4456 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4457 pFT_Vector_Unit(&vecAngle
, angle
);
4458 rotationMat
.xx
= vecAngle
.x
;
4459 rotationMat
.xy
= -vecAngle
.y
;
4460 rotationMat
.yx
= -rotationMat
.xy
;
4461 rotationMat
.yy
= rotationMat
.xx
;
4463 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4464 needsTransform
= TRUE
;
4467 /* World transform */
4468 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4471 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4472 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4473 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4474 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4475 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4476 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4477 needsTransform
= TRUE
;
4480 /* Extra transformation specified by caller */
4481 if (lpmat
&& !is_identity_MAT2(lpmat
))
4484 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4485 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
4486 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
4487 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4488 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4489 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4490 needsTransform
= TRUE
;
4493 if (needsTransform
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
))
4494 load_flags
|= FT_LOAD_NO_BITMAP
;
4496 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4499 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4500 LeaveCriticalSection( &freetype_cs
);
4504 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4505 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4507 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
) + 63) >> 6;
4509 bbx
= (right
- left
) >> 6;
4511 if(!needsTransform
) {
4512 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4513 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4514 ft_face
->glyph
->metrics
.height
) & -64;
4515 lpgm
->gmCellIncX
= adv
;
4516 lpgm
->gmCellIncY
= 0;
4520 for(xc
= 0; xc
< 2; xc
++) {
4521 for(yc
= 0; yc
< 2; yc
++) {
4522 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4523 xc
* ft_face
->glyph
->metrics
.width
);
4524 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4525 yc
* ft_face
->glyph
->metrics
.height
;
4526 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4527 pFT_Vector_Transform(&vec
, &transMat
);
4528 if(xc
== 0 && yc
== 0) {
4529 left
= right
= vec
.x
;
4530 top
= bottom
= vec
.y
;
4532 if(vec
.x
< left
) left
= vec
.x
;
4533 else if(vec
.x
> right
) right
= vec
.x
;
4534 if(vec
.y
< bottom
) bottom
= vec
.y
;
4535 else if(vec
.y
> top
) top
= vec
.y
;
4540 right
= (right
+ 63) & -64;
4541 bottom
= bottom
& -64;
4542 top
= (top
+ 63) & -64;
4544 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4545 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4547 pFT_Vector_Transform(&vec
, &transMat
);
4548 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4549 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4551 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4553 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4554 adv
= (vec
.x
+63) >> 6;
4556 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4557 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4558 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4559 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4561 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4562 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4563 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4565 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4566 (!lpmat
|| is_identity_MAT2(lpmat
))) /* don't cache custom transforms */
4568 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4569 FONT_GM(font
,original_index
)->adv
= adv
;
4570 FONT_GM(font
,original_index
)->lsb
= lsb
;
4571 FONT_GM(font
,original_index
)->bbx
= bbx
;
4572 FONT_GM(font
,original_index
)->init
= TRUE
;
4575 if(format
== GGO_METRICS
)
4577 LeaveCriticalSection( &freetype_cs
);
4578 return 1; /* FIXME */
4581 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
&& format
!= WINE_GGO_GRAY16_BITMAP
) {
4582 TRACE("loaded a bitmap\n");
4583 LeaveCriticalSection( &freetype_cs
);
4589 width
= lpgm
->gmBlackBoxX
;
4590 height
= lpgm
->gmBlackBoxY
;
4591 pitch
= ((width
+ 31) >> 5) << 2;
4592 needed
= pitch
* height
;
4594 if(!buf
|| !buflen
) break;
4596 switch(ft_face
->glyph
->format
) {
4597 case ft_glyph_format_bitmap
:
4599 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4600 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4601 INT h
= ft_face
->glyph
->bitmap
.rows
;
4603 memcpy(dst
, src
, w
);
4604 src
+= ft_face
->glyph
->bitmap
.pitch
;
4610 case ft_glyph_format_outline
:
4611 ft_bitmap
.width
= width
;
4612 ft_bitmap
.rows
= height
;
4613 ft_bitmap
.pitch
= pitch
;
4614 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4615 ft_bitmap
.buffer
= buf
;
4618 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4620 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4622 /* Note: FreeType will only set 'black' bits for us. */
4623 memset(buf
, 0, needed
);
4624 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4628 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4629 LeaveCriticalSection( &freetype_cs
);
4634 case GGO_GRAY2_BITMAP
:
4635 case GGO_GRAY4_BITMAP
:
4636 case GGO_GRAY8_BITMAP
:
4637 case WINE_GGO_GRAY16_BITMAP
:
4639 unsigned int mult
, row
, col
;
4642 width
= lpgm
->gmBlackBoxX
;
4643 height
= lpgm
->gmBlackBoxY
;
4644 pitch
= (width
+ 3) / 4 * 4;
4645 needed
= pitch
* height
;
4647 if(!buf
|| !buflen
) break;
4649 switch(ft_face
->glyph
->format
) {
4650 case ft_glyph_format_bitmap
:
4652 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4653 INT h
= ft_face
->glyph
->bitmap
.rows
;
4656 for(x
= 0; x
< pitch
; x
++)
4658 if(x
< ft_face
->glyph
->bitmap
.width
)
4659 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4663 src
+= ft_face
->glyph
->bitmap
.pitch
;
4666 LeaveCriticalSection( &freetype_cs
);
4669 case ft_glyph_format_outline
:
4671 ft_bitmap
.width
= width
;
4672 ft_bitmap
.rows
= height
;
4673 ft_bitmap
.pitch
= pitch
;
4674 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4675 ft_bitmap
.buffer
= buf
;
4678 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4680 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4682 memset(ft_bitmap
.buffer
, 0, buflen
);
4684 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4686 if(format
== GGO_GRAY2_BITMAP
)
4688 else if(format
== GGO_GRAY4_BITMAP
)
4690 else if(format
== GGO_GRAY8_BITMAP
)
4692 else /* format == WINE_GGO_GRAY16_BITMAP */
4694 LeaveCriticalSection( &freetype_cs
);
4700 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4701 LeaveCriticalSection( &freetype_cs
);
4706 for(row
= 0; row
< height
; row
++) {
4708 for(col
= 0; col
< width
; col
++, ptr
++) {
4709 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4718 int contour
, point
= 0, first_pt
;
4719 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4720 TTPOLYGONHEADER
*pph
;
4722 DWORD pph_start
, cpfx
, type
;
4724 if(buflen
== 0) buf
= NULL
;
4726 if (needsTransform
&& buf
) {
4727 pFT_Outline_Transform(outline
, &transMat
);
4730 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4732 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4735 pph
->dwType
= TT_POLYGON_TYPE
;
4736 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4738 needed
+= sizeof(*pph
);
4740 while(point
<= outline
->contours
[contour
]) {
4741 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4742 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4743 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
4747 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4750 } while(point
<= outline
->contours
[contour
] &&
4751 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4752 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4753 /* At the end of a contour Windows adds the start point, but
4755 if(point
> outline
->contours
[contour
] &&
4756 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4758 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
4760 } else if(point
<= outline
->contours
[contour
] &&
4761 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4762 /* add closing pt for bezier */
4764 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4772 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4775 pph
->cb
= needed
- pph_start
;
4781 /* Convert the quadratic Beziers to cubic Beziers.
4782 The parametric eqn for a cubic Bezier is, from PLRM:
4783 r(t) = at^3 + bt^2 + ct + r0
4784 with the control points:
4789 A quadratic Beizer has the form:
4790 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4792 So equating powers of t leads to:
4793 r1 = 2/3 p1 + 1/3 p0
4794 r2 = 2/3 p1 + 1/3 p2
4795 and of course r0 = p0, r3 = p2
4798 int contour
, point
= 0, first_pt
;
4799 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
4800 TTPOLYGONHEADER
*pph
;
4802 DWORD pph_start
, cpfx
, type
;
4803 FT_Vector cubic_control
[4];
4804 if(buflen
== 0) buf
= NULL
;
4806 if (needsTransform
&& buf
) {
4807 pFT_Outline_Transform(outline
, &transMat
);
4810 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
4812 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
4815 pph
->dwType
= TT_POLYGON_TYPE
;
4816 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
4818 needed
+= sizeof(*pph
);
4820 while(point
<= outline
->contours
[contour
]) {
4821 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
4822 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
4823 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
4826 if(type
== TT_PRIM_LINE
) {
4828 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
4832 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4835 /* FIXME: Possible optimization in endpoint calculation
4836 if there are two consecutive curves */
4837 cubic_control
[0] = outline
->points
[point
-1];
4838 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
4839 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
4840 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
4841 cubic_control
[0].x
>>= 1;
4842 cubic_control
[0].y
>>= 1;
4844 if(point
+1 > outline
->contours
[contour
])
4845 cubic_control
[3] = outline
->points
[first_pt
];
4847 cubic_control
[3] = outline
->points
[point
+1];
4848 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
4849 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
4850 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
4851 cubic_control
[3].x
>>= 1;
4852 cubic_control
[3].y
>>= 1;
4855 /* r1 = 1/3 p0 + 2/3 p1
4856 r2 = 1/3 p2 + 2/3 p1 */
4857 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
4858 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
4859 cubic_control
[2] = cubic_control
[1];
4860 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
4861 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
4862 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
4863 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
4865 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
4866 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
4867 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
4872 } while(point
<= outline
->contours
[contour
] &&
4873 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
4874 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
4875 /* At the end of a contour Windows adds the start point,
4876 but only for Beziers and we've already done that.
4878 if(point
<= outline
->contours
[contour
] &&
4879 outline
->tags
[point
] & FT_Curve_Tag_On
) {
4880 /* This is the closing pt of a bezier, but we've already
4881 added it, so just inc point and carry on */
4888 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
4891 pph
->cb
= needed
- pph_start
;
4897 FIXME("Unsupported format %d\n", format
);
4898 LeaveCriticalSection( &freetype_cs
);
4901 LeaveCriticalSection( &freetype_cs
);
4905 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
4907 FT_Face ft_face
= font
->ft_face
;
4908 #ifdef HAVE_FREETYPE_FTWINFNT_H
4909 FT_WinFNT_HeaderRec winfnt_header
;
4911 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
4912 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
4913 font
->potm
->otmSize
= size
;
4915 #define TM font->potm->otmTextMetrics
4916 #ifdef HAVE_FREETYPE_FTWINFNT_H
4917 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
4919 TM
.tmHeight
= winfnt_header
.pixel_height
;
4920 TM
.tmAscent
= winfnt_header
.ascent
;
4921 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
4922 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
4923 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
4924 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
4925 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
4926 TM
.tmWeight
= winfnt_header
.weight
;
4928 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
4929 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
4930 TM
.tmFirstChar
= winfnt_header
.first_char
;
4931 TM
.tmLastChar
= winfnt_header
.last_char
;
4932 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
4933 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
4934 TM
.tmItalic
= winfnt_header
.italic
;
4935 TM
.tmUnderlined
= font
->underline
;
4936 TM
.tmStruckOut
= font
->strikeout
;
4937 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
4938 TM
.tmCharSet
= winfnt_header
.charset
;
4943 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
4944 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
4945 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4946 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
4947 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
4948 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
4949 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
4950 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
4952 TM
.tmDigitizedAspectX
= 96; /* FIXME */
4953 TM
.tmDigitizedAspectY
= 96; /* FIXME */
4955 TM
.tmLastChar
= 255;
4956 TM
.tmDefaultChar
= 32;
4957 TM
.tmBreakChar
= 32;
4958 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
4959 TM
.tmUnderlined
= font
->underline
;
4960 TM
.tmStruckOut
= font
->strikeout
;
4961 /* NB inverted meaning of TMPF_FIXED_PITCH */
4962 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
4963 TM
.tmCharSet
= font
->charset
;
4971 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
4973 double scale_x
, scale_y
;
4977 scale_x
= (double)font
->aveWidth
;
4978 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4981 scale_x
= font
->scale_y
;
4983 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
4984 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
4986 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
4987 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
4989 SCALE_Y(ptm
->tmHeight
);
4990 SCALE_Y(ptm
->tmAscent
);
4991 SCALE_Y(ptm
->tmDescent
);
4992 SCALE_Y(ptm
->tmInternalLeading
);
4993 SCALE_Y(ptm
->tmExternalLeading
);
4994 SCALE_Y(ptm
->tmOverhang
);
4996 SCALE_X(ptm
->tmAveCharWidth
);
4997 SCALE_X(ptm
->tmMaxCharWidth
);
5003 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5005 double scale_x
, scale_y
;
5009 scale_x
= (double)font
->aveWidth
;
5010 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5013 scale_x
= font
->scale_y
;
5015 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5016 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5018 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5020 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5021 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5023 SCALE_Y(potm
->otmAscent
);
5024 SCALE_Y(potm
->otmDescent
);
5025 SCALE_Y(potm
->otmLineGap
);
5026 SCALE_Y(potm
->otmsCapEmHeight
);
5027 SCALE_Y(potm
->otmsXHeight
);
5028 SCALE_Y(potm
->otmrcFontBox
.top
);
5029 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5030 SCALE_X(potm
->otmrcFontBox
.left
);
5031 SCALE_X(potm
->otmrcFontBox
.right
);
5032 SCALE_Y(potm
->otmMacAscent
);
5033 SCALE_Y(potm
->otmMacDescent
);
5034 SCALE_Y(potm
->otmMacLineGap
);
5035 SCALE_X(potm
->otmptSubscriptSize
.x
);
5036 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5037 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5038 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5039 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5040 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5041 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5042 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5043 SCALE_Y(potm
->otmsStrikeoutSize
);
5044 SCALE_Y(potm
->otmsStrikeoutPosition
);
5045 SCALE_Y(potm
->otmsUnderscoreSize
);
5046 SCALE_Y(potm
->otmsUnderscorePosition
);
5052 /*************************************************************
5053 * WineEngGetTextMetrics
5056 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5058 EnterCriticalSection( &freetype_cs
);
5060 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5061 if(!get_bitmap_text_metrics(font
))
5063 LeaveCriticalSection( &freetype_cs
);
5069 LeaveCriticalSection( &freetype_cs
);
5072 *ptm
= font
->potm
->otmTextMetrics
;
5073 scale_font_metrics(font
, ptm
);
5074 LeaveCriticalSection( &freetype_cs
);
5079 /*************************************************************
5080 * WineEngGetOutlineTextMetrics
5083 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5084 OUTLINETEXTMETRICW
*potm
)
5086 FT_Face ft_face
= font
->ft_face
;
5087 UINT needed
, lenfam
, lensty
, ret
;
5089 TT_HoriHeader
*pHori
;
5090 TT_Postscript
*pPost
;
5091 FT_Fixed x_scale
, y_scale
;
5092 WCHAR
*family_nameW
, *style_nameW
;
5093 static const WCHAR spaceW
[] = {' ', '\0'};
5095 INT ascent
, descent
;
5097 TRACE("font=%p\n", font
);
5099 if(!FT_IS_SCALABLE(ft_face
))
5102 EnterCriticalSection( &freetype_cs
);
5105 if(cbSize
>= font
->potm
->otmSize
)
5107 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5108 scale_outline_font_metrics(font
, potm
);
5110 LeaveCriticalSection( &freetype_cs
);
5111 return font
->potm
->otmSize
;
5115 needed
= sizeof(*potm
);
5117 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5118 family_nameW
= strdupW(font
->name
);
5120 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5122 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5123 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5124 style_nameW
, lensty
/sizeof(WCHAR
));
5126 /* These names should be read from the TT name table */
5128 /* length of otmpFamilyName */
5131 /* length of otmpFaceName */
5132 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5133 needed
+= lenfam
; /* just the family name */
5135 needed
+= lenfam
+ lensty
; /* family + " " + style */
5138 /* length of otmpStyleName */
5141 /* length of otmpFullName */
5142 needed
+= lenfam
+ lensty
;
5145 x_scale
= ft_face
->size
->metrics
.x_scale
;
5146 y_scale
= ft_face
->size
->metrics
.y_scale
;
5148 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5150 FIXME("Can't find OS/2 table - not TT font?\n");
5155 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5157 FIXME("Can't find HHEA table - not TT font?\n");
5162 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5164 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",
5165 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5166 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5167 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5168 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5169 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5171 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5172 font
->potm
->otmSize
= needed
;
5174 #define TM font->potm->otmTextMetrics
5176 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5177 ascent
= pHori
->Ascender
;
5178 descent
= -pHori
->Descender
;
5180 ascent
= pOS2
->usWinAscent
;
5181 descent
= pOS2
->usWinDescent
;
5185 TM
.tmAscent
= font
->yMax
;
5186 TM
.tmDescent
= -font
->yMin
;
5187 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5189 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5190 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5191 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5192 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5195 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5198 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5200 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5201 ((ascent
+ descent
) -
5202 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5204 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5205 if (TM
.tmAveCharWidth
== 0) {
5206 TM
.tmAveCharWidth
= 1;
5208 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5209 TM
.tmWeight
= (font
->fake_bold
|| (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)) ? FW_BOLD
: FW_REGULAR
;
5211 TM
.tmDigitizedAspectX
= 300;
5212 TM
.tmDigitizedAspectY
= 300;
5213 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5214 * symbol range to 0 - f0ff
5216 if (font
->charset
== SYMBOL_CHARSET
)
5219 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
5223 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
5224 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0xffff;
5226 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
5227 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
5228 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5229 TM
.tmUnderlined
= font
->underline
;
5230 TM
.tmStruckOut
= font
->strikeout
;
5232 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5233 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5234 (pOS2
->version
== 0xFFFFU
||
5235 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5236 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5238 TM
.tmPitchAndFamily
= 0;
5240 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
5241 case PAN_FAMILY_SCRIPT
:
5242 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5244 case PAN_FAMILY_DECORATIVE
:
5245 case PAN_FAMILY_PICTORIAL
:
5246 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5248 case PAN_FAMILY_TEXT_DISPLAY
:
5249 if(TM
.tmPitchAndFamily
== 0) /* fixed */
5250 TM
.tmPitchAndFamily
= FF_MODERN
;
5252 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
5253 case PAN_SERIF_NORMAL_SANS
:
5254 case PAN_SERIF_OBTUSE_SANS
:
5255 case PAN_SERIF_PERP_SANS
:
5256 TM
.tmPitchAndFamily
|= FF_SWISS
;
5259 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5264 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5267 if(FT_IS_SCALABLE(ft_face
))
5268 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5270 if(FT_IS_SFNT(ft_face
))
5272 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5273 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5275 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5278 TM
.tmCharSet
= font
->charset
;
5280 font
->potm
->otmFiller
= 0;
5281 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5282 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5283 font
->potm
->otmfsType
= pOS2
->fsType
;
5284 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5285 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5286 font
->potm
->otmItalicAngle
= 0; /* POST table */
5287 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5288 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5289 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5290 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5291 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5292 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5293 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5294 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5295 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5296 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5297 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5298 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5299 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5300 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5301 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5302 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5303 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5304 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5305 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5306 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5307 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5308 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5309 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5310 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5312 font
->potm
->otmsUnderscoreSize
= 0;
5313 font
->potm
->otmsUnderscorePosition
= 0;
5315 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5316 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5320 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5321 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5322 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5323 strcpyW((WCHAR
*)cp
, family_nameW
);
5325 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5326 strcpyW((WCHAR
*)cp
, style_nameW
);
5328 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5329 strcpyW((WCHAR
*)cp
, family_nameW
);
5330 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5331 strcatW((WCHAR
*)cp
, spaceW
);
5332 strcatW((WCHAR
*)cp
, style_nameW
);
5333 cp
+= lenfam
+ lensty
;
5336 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5337 strcpyW((WCHAR
*)cp
, family_nameW
);
5338 strcatW((WCHAR
*)cp
, spaceW
);
5339 strcatW((WCHAR
*)cp
, style_nameW
);
5342 if(potm
&& needed
<= cbSize
)
5344 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5345 scale_outline_font_metrics(font
, potm
);
5349 HeapFree(GetProcessHeap(), 0, style_nameW
);
5350 HeapFree(GetProcessHeap(), 0, family_nameW
);
5352 LeaveCriticalSection( &freetype_cs
);
5356 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5358 HFONTLIST
*hfontlist
;
5359 child
->font
= alloc_font();
5360 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5361 if(!child
->font
->ft_face
)
5363 free_font(child
->font
);
5368 child
->font
->font_desc
= font
->font_desc
;
5369 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5370 child
->font
->orientation
= font
->orientation
;
5371 child
->font
->scale_y
= font
->scale_y
;
5372 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5373 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5374 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5375 child
->font
->base_font
= font
;
5376 list_add_head(&child_font_list
, &child
->font
->entry
);
5377 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5381 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5384 CHILD_FONT
*child_font
;
5387 font
= font
->base_font
;
5389 *linked_font
= font
;
5391 if((*glyph
= get_glyph_index(font
, c
)))
5394 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5396 if(!child_font
->font
)
5397 if(!load_child_font(font
, child_font
))
5400 if(!child_font
->font
->ft_face
)
5402 g
= get_glyph_index(child_font
->font
, c
);
5406 *linked_font
= child_font
->font
;
5413 /*************************************************************
5414 * WineEngGetCharWidth
5417 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5422 FT_UInt glyph_index
;
5423 GdiFont
*linked_font
;
5425 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5427 EnterCriticalSection( &freetype_cs
);
5428 for(c
= firstChar
; c
<= lastChar
; c
++) {
5429 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5430 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5431 &gm
, 0, NULL
, NULL
);
5432 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5434 LeaveCriticalSection( &freetype_cs
);
5438 /*************************************************************
5439 * WineEngGetCharABCWidths
5442 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5447 FT_UInt glyph_index
;
5448 GdiFont
*linked_font
;
5450 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5452 if(!FT_IS_SCALABLE(font
->ft_face
))
5455 EnterCriticalSection( &freetype_cs
);
5457 for(c
= firstChar
; c
<= lastChar
; c
++) {
5458 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5459 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5460 &gm
, 0, NULL
, NULL
);
5461 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5462 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5463 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5464 FONT_GM(linked_font
,glyph_index
)->bbx
;
5466 LeaveCriticalSection( &freetype_cs
);
5470 /*************************************************************
5471 * WineEngGetCharABCWidthsI
5474 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5479 FT_UInt glyph_index
;
5480 GdiFont
*linked_font
;
5482 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5485 EnterCriticalSection( &freetype_cs
);
5487 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5489 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5490 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5491 &gm
, 0, NULL
, NULL
);
5492 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5493 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5494 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5495 - FONT_GM(linked_font
,c
)->bbx
;
5498 for(c
= 0; c
< count
; c
++) {
5499 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5500 &gm
, 0, NULL
, NULL
);
5501 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5502 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5503 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5504 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5507 LeaveCriticalSection( &freetype_cs
);
5511 /*************************************************************
5512 * WineEngGetTextExtentExPoint
5515 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5516 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5522 FT_UInt glyph_index
;
5523 GdiFont
*linked_font
;
5525 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
5528 EnterCriticalSection( &freetype_cs
);
5531 WineEngGetTextMetrics(font
, &tm
);
5532 size
->cy
= tm
.tmHeight
;
5534 for(idx
= 0; idx
< count
; idx
++) {
5535 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
5536 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5537 &gm
, 0, NULL
, NULL
);
5538 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
5540 if (! pnfit
|| ext
<= max_ext
) {
5550 LeaveCriticalSection( &freetype_cs
);
5551 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5555 /*************************************************************
5556 * WineEngGetTextExtentExPointI
5559 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
5560 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5567 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
5569 EnterCriticalSection( &freetype_cs
);
5572 WineEngGetTextMetrics(font
, &tm
);
5573 size
->cy
= tm
.tmHeight
;
5575 for(idx
= 0; idx
< count
; idx
++) {
5576 WineEngGetGlyphOutline(font
, indices
[idx
],
5577 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
5579 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
5581 if (! pnfit
|| ext
<= max_ext
) {
5591 LeaveCriticalSection( &freetype_cs
);
5592 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
5596 /*************************************************************
5597 * WineEngGetFontData
5600 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
5603 FT_Face ft_face
= font
->ft_face
;
5607 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
5608 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
5609 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
5611 if(!FT_IS_SFNT(ft_face
))
5619 if(table
) { /* MS tags differ in endianness from FT ones */
5620 table
= table
>> 24 | table
<< 24 |
5621 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
5624 /* make sure value of len is the value freetype says it needs */
5627 FT_ULong needed
= 0;
5628 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
5629 if( !err
&& needed
< len
) len
= needed
;
5631 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
5634 TRACE("Can't find table %c%c%c%c\n",
5635 /* bytes were reversed */
5636 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
5637 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
5643 /*************************************************************
5644 * WineEngGetTextFace
5647 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
5649 INT n
= strlenW(font
->name
) + 1;
5651 lstrcpynW(str
, font
->name
, count
);
5652 return min(count
, n
);
5657 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
5659 if (fs
) *fs
= font
->fs
;
5660 return font
->charset
;
5663 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
5665 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
5666 struct list
*first_hfont
;
5669 EnterCriticalSection( &freetype_cs
);
5670 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
5671 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
5672 if(font
== linked_font
)
5673 *new_hfont
= dc
->hFont
;
5676 first_hfont
= list_head(&linked_font
->hfontlist
);
5677 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
5679 LeaveCriticalSection( &freetype_cs
);
5683 /* Retrieve a list of supported Unicode ranges for a given font.
5684 * Can be called with NULL gs to calculate the buffer size. Returns
5685 * the number of ranges found.
5687 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
5689 DWORD num_ranges
= 0;
5691 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5694 FT_ULong char_code
, char_code_prev
;
5697 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
5699 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5700 face
->num_glyphs
, glyph_code
, char_code
);
5702 if (!glyph_code
) return 0;
5706 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
5707 gs
->ranges
[0].cGlyphs
= 0;
5708 gs
->cGlyphsSupported
= 0;
5714 if (char_code
< char_code_prev
)
5716 ERR("expected increasing char code from FT_Get_Next_Char\n");
5719 if (char_code
- char_code_prev
> 1)
5724 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
5725 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
5726 gs
->cGlyphsSupported
++;
5731 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
5732 gs
->cGlyphsSupported
++;
5734 char_code_prev
= char_code
;
5735 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
5739 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
5744 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
5747 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
5749 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
5752 glyphset
->cbThis
= size
;
5753 glyphset
->cRanges
= num_ranges
;
5758 /*************************************************************
5761 BOOL
WineEngFontIsLinked(GdiFont
*font
)
5764 EnterCriticalSection( &freetype_cs
);
5765 ret
= !list_empty(&font
->child_fonts
);
5766 LeaveCriticalSection( &freetype_cs
);
5770 static BOOL
is_hinting_enabled(void)
5772 /* Use the >= 2.2.0 function if available */
5773 if(pFT_Get_TrueType_Engine_Type
)
5775 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
5776 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
5778 #ifdef FT_DRIVER_HAS_HINTER
5783 /* otherwise if we've been compiled with < 2.2.0 headers
5784 use the internal macro */
5785 mod
= pFT_Get_Module(library
, "truetype");
5786 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
5794 /*************************************************************************
5795 * GetRasterizerCaps (GDI32.@)
5797 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5799 static int hinting
= -1;
5803 hinting
= is_hinting_enabled();
5804 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
5807 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5808 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
5809 lprs
->nLanguageID
= 0;
5813 /*************************************************************
5814 * WineEngRealizationInfo
5816 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
5818 FIXME("(%p, %p): stub!\n", font
, info
);
5821 if(FT_IS_SCALABLE(font
->ft_face
))
5824 info
->cache_num
= font
->cache_num
;
5825 info
->unknown2
= -1;
5829 /*************************************************************************
5830 * Kerning support for TrueType fonts
5832 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
5834 struct TT_kern_table
5840 struct TT_kern_subtable
5849 USHORT horizontal
: 1;
5851 USHORT cross_stream
: 1;
5852 USHORT override
: 1;
5853 USHORT reserved1
: 4;
5859 struct TT_format0_kern_subtable
5863 USHORT entrySelector
;
5874 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
5875 const struct TT_format0_kern_subtable
*tt_f0_ks
,
5876 const USHORT
*glyph_to_char
,
5877 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
5880 const struct TT_kern_pair
*tt_kern_pair
;
5882 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
5884 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
5886 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
5887 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
5888 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
5890 if (!kern_pair
|| !cPairs
)
5893 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
5895 nPairs
= min(nPairs
, cPairs
);
5897 for (i
= 0; i
< nPairs
; i
++)
5899 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
5900 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
5901 /* this algorithm appears to better match what Windows does */
5902 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
5903 if (kern_pair
->iKernAmount
< 0)
5905 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
5906 kern_pair
->iKernAmount
-= font
->ppem
;
5908 else if (kern_pair
->iKernAmount
> 0)
5910 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
5911 kern_pair
->iKernAmount
+= font
->ppem
;
5913 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
5915 TRACE("left %u right %u value %d\n",
5916 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
5920 TRACE("copied %u entries\n", nPairs
);
5924 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5928 const struct TT_kern_table
*tt_kern_table
;
5929 const struct TT_kern_subtable
*tt_kern_subtable
;
5931 USHORT
*glyph_to_char
;
5933 EnterCriticalSection( &freetype_cs
);
5934 if (font
->total_kern_pairs
!= (DWORD
)-1)
5936 if (cPairs
&& kern_pair
)
5938 cPairs
= min(cPairs
, font
->total_kern_pairs
);
5939 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
5940 LeaveCriticalSection( &freetype_cs
);
5943 LeaveCriticalSection( &freetype_cs
);
5944 return font
->total_kern_pairs
;
5947 font
->total_kern_pairs
= 0;
5949 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
5951 if (length
== GDI_ERROR
)
5953 TRACE("no kerning data in the font\n");
5954 LeaveCriticalSection( &freetype_cs
);
5958 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
5961 WARN("Out of memory\n");
5962 LeaveCriticalSection( &freetype_cs
);
5966 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
5968 /* build a glyph index to char code map */
5969 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
5972 WARN("Out of memory allocating a glyph index to char code map\n");
5973 HeapFree(GetProcessHeap(), 0, buf
);
5974 LeaveCriticalSection( &freetype_cs
);
5978 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
5984 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
5986 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5987 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
5991 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5993 /* FIXME: This doesn't match what Windows does: it does some fancy
5994 * things with duplicate glyph index to char code mappings, while
5995 * we just avoid overriding existing entries.
5997 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
5998 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6000 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6007 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6008 for (n
= 0; n
<= 65535; n
++)
6009 glyph_to_char
[n
] = (USHORT
)n
;
6012 tt_kern_table
= buf
;
6013 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6014 TRACE("version %u, nTables %u\n",
6015 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6017 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6019 for (i
= 0; i
< nTables
; i
++)
6021 struct TT_kern_subtable tt_kern_subtable_copy
;
6023 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6024 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6025 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6027 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6028 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6029 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6031 /* According to the TrueType specification this is the only format
6032 * that will be properly interpreted by Windows and OS/2
6034 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6036 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6038 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6039 glyph_to_char
, NULL
, 0);
6040 font
->total_kern_pairs
+= new_chunk
;
6042 if (!font
->kern_pairs
)
6043 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6044 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6046 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6047 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6049 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6050 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6053 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6055 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6058 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6059 HeapFree(GetProcessHeap(), 0, buf
);
6061 if (cPairs
&& kern_pair
)
6063 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6064 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6065 LeaveCriticalSection( &freetype_cs
);
6068 LeaveCriticalSection( &freetype_cs
);
6069 return font
->total_kern_pairs
;
6072 #else /* HAVE_FREETYPE */
6074 /*************************************************************************/
6076 BOOL
WineEngInit(void)
6080 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6084 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6089 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6094 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6095 LPWORD pgi
, DWORD flags
)
6100 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6101 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6104 ERR("called but we don't have FreeType\n");
6108 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6110 ERR("called but we don't have FreeType\n");
6114 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6115 OUTLINETEXTMETRICW
*potm
)
6117 ERR("called but we don't have FreeType\n");
6121 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6124 ERR("called but we don't have FreeType\n");
6128 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6131 ERR("called but we don't have FreeType\n");
6135 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6138 ERR("called but we don't have FreeType\n");
6142 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6143 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6145 ERR("called but we don't have FreeType\n");
6149 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6150 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6152 ERR("called but we don't have FreeType\n");
6156 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6159 ERR("called but we don't have FreeType\n");
6163 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6165 ERR("called but we don't have FreeType\n");
6169 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6175 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6181 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6187 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6190 return DEFAULT_CHARSET
;
6193 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6198 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6200 FIXME("(%p, %p): stub\n", font
, glyphset
);
6204 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6209 /*************************************************************************
6210 * GetRasterizerCaps (GDI32.@)
6212 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6214 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6216 lprs
->nLanguageID
= 0;
6220 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6222 ERR("called but we don't have FreeType\n");
6226 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6228 ERR("called but we don't have FreeType\n");
6232 #endif /* HAVE_FREETYPE */