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_TTNAMEID_H
114 #include <freetype/ttnameid.h>
116 #ifdef HAVE_FREETYPE_FTOUTLN_H
117 #include <freetype/ftoutln.h>
119 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
120 #include <freetype/internal/sfnt.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType
;
144 static FT_Library library
= 0;
151 static FT_Version_t FT_Version
;
152 static DWORD FT_SimpleVersion
;
154 static void *ft_handle
= NULL
;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit
);
158 MAKE_FUNCPTR(FT_Done_Face
);
159 MAKE_FUNCPTR(FT_Get_Char_Index
);
160 MAKE_FUNCPTR(FT_Get_Module
);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
164 MAKE_FUNCPTR(FT_Init_FreeType
);
165 MAKE_FUNCPTR(FT_Load_Glyph
);
166 MAKE_FUNCPTR(FT_Matrix_Multiply
);
167 #ifdef FT_MULFIX_INLINED
168 #define pFT_MulFix FT_MULFIX_INLINED
170 MAKE_FUNCPTR(FT_MulFix
);
172 MAKE_FUNCPTR(FT_New_Face
);
173 MAKE_FUNCPTR(FT_New_Memory_Face
);
174 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
175 MAKE_FUNCPTR(FT_Outline_Transform
);
176 MAKE_FUNCPTR(FT_Outline_Translate
);
177 MAKE_FUNCPTR(FT_Select_Charmap
);
178 MAKE_FUNCPTR(FT_Set_Charmap
);
179 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
180 MAKE_FUNCPTR(FT_Vector_Transform
);
181 MAKE_FUNCPTR(FT_Render_Glyph
);
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_FTLCDFIL_H
188 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
190 #ifdef HAVE_FREETYPE_FTWINFNT_H
191 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
194 #ifdef SONAME_LIBFONTCONFIG
195 #include <fontconfig/fontconfig.h>
196 MAKE_FUNCPTR(FcConfigGetCurrent
);
197 MAKE_FUNCPTR(FcFontList
);
198 MAKE_FUNCPTR(FcFontSetDestroy
);
199 MAKE_FUNCPTR(FcInit
);
200 MAKE_FUNCPTR(FcObjectSetAdd
);
201 MAKE_FUNCPTR(FcObjectSetCreate
);
202 MAKE_FUNCPTR(FcObjectSetDestroy
);
203 MAKE_FUNCPTR(FcPatternCreate
);
204 MAKE_FUNCPTR(FcPatternDestroy
);
205 MAKE_FUNCPTR(FcPatternGetBool
);
206 MAKE_FUNCPTR(FcPatternGetString
);
212 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
213 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
214 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
217 #ifndef ft_encoding_none
218 #define FT_ENCODING_NONE ft_encoding_none
220 #ifndef ft_encoding_ms_symbol
221 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
223 #ifndef ft_encoding_unicode
224 #define FT_ENCODING_UNICODE ft_encoding_unicode
226 #ifndef ft_encoding_apple_roman
227 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
230 #ifdef WORDS_BIGENDIAN
231 #define GET_BE_WORD(x) (x)
233 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
236 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
243 FT_Short internal_leading
;
246 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
247 So to let this compile on older versions of FreeType we'll define the
248 new structure here. */
250 FT_Short height
, width
;
251 FT_Pos size
, x_ppem
, y_ppem
;
257 NEWTEXTMETRICEXW ntm
;
261 typedef struct tagFace
{
266 DWORD font_data_size
;
269 FONTSIGNATURE fs_links
;
271 FT_Fixed font_version
;
273 Bitmap_Size size
; /* set if face is a bitmap */
274 BOOL external
; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily
*family
;
276 /* Cached data for Enum */
277 struct enum_data
*cached_enum_data
;
280 typedef struct tagFamily
{
282 const WCHAR
*FamilyName
;
288 INT adv
; /* These three hold to widths of the unrotated chars */
306 typedef struct tagHFONTLIST
{
321 struct list hfontlist
;
322 OUTLINETEXTMETRICW
*potm
;
323 DWORD total_kern_pairs
;
324 KERNINGPAIR
*kern_pairs
;
325 struct list child_fonts
;
327 /* the following members can be accessed without locking, they are never modified after creation */
329 struct font_mapping
*mapping
;
352 const WCHAR
*font_name
;
356 #define GM_BLOCK_SIZE 128
357 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
359 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
360 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
361 #define UNUSED_CACHE_SIZE 10
362 static struct list child_font_list
= LIST_INIT(child_font_list
);
363 static struct list system_links
= LIST_INIT(system_links
);
365 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
367 static struct list font_list
= LIST_INIT(font_list
);
369 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
370 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
371 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
373 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
374 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
375 'W','i','n','d','o','w','s','\\',
376 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
377 'F','o','n','t','s','\0'};
379 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
380 'W','i','n','d','o','w','s',' ','N','T','\\',
381 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
382 'F','o','n','t','s','\0'};
384 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
385 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
386 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
387 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
389 static const WCHAR
* const SystemFontValues
[4] = {
396 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
397 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
399 /* Interesting and well-known (frequently-assumed!) font names */
400 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
401 static const WCHAR Microsoft_Sans_Serif
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
402 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
403 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
404 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
405 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
406 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
407 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
409 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
410 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
411 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
412 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
413 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
414 'E','u','r','o','p','e','a','n','\0'};
415 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
416 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
417 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
418 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
419 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
420 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
421 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
422 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
423 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
424 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
425 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
426 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
428 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
438 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
446 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
455 typedef struct tagFontSubst
{
471 static struct list mappings_list
= LIST_INIT( mappings_list
);
473 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
475 static CRITICAL_SECTION freetype_cs
;
476 static CRITICAL_SECTION_DEBUG critsect_debug
=
479 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
480 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
482 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
484 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
486 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
487 static BOOL use_default_fallback
= FALSE
;
489 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
491 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
492 'W','i','n','d','o','w','s',' ','N','T','\\',
493 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
494 'S','y','s','t','e','m','L','i','n','k',0};
496 /****************************************
497 * Notes on .fon files
499 * The fonts System, FixedSys and Terminal are special. There are typically multiple
500 * versions installed for different resolutions and codepages. Windows stores which one to use
501 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
503 * FIXEDFON.FON FixedSys
505 * OEMFONT.FON Terminal
506 * LogPixels Current dpi set by the display control panel applet
507 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
508 * also has a LogPixels value that appears to mirror this)
510 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
511 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
512 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
513 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
514 * so that makes sense.
516 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
517 * to be mapped into the registry on Windows 2000 at least).
520 * ega80woa.fon=ega80850.fon
521 * ega40woa.fon=ega40850.fon
522 * cga80woa.fon=cga80850.fon
523 * cga40woa.fon=cga40850.fon
526 /* These are all structures needed for the GSUB table */
528 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
529 #define TATEGAKI_LOWER_BOUND 0x02F1
545 GSUB_ScriptRecord ScriptRecord
[1];
551 } GSUB_LangSysRecord
;
556 GSUB_LangSysRecord LangSysRecord
[1];
560 WORD LookupOrder
; /* Reserved */
561 WORD ReqFeatureIndex
;
563 WORD FeatureIndex
[1];
569 } GSUB_FeatureRecord
;
573 GSUB_FeatureRecord FeatureRecord
[1];
577 WORD FeatureParams
; /* Reserved */
579 WORD LookupListIndex
[1];
598 } GSUB_CoverageFormat1
;
603 WORD StartCoverageIndex
;
609 GSUB_RangeRecord RangeRecord
[1];
610 } GSUB_CoverageFormat2
;
613 WORD SubstFormat
; /* = 1 */
616 } GSUB_SingleSubstFormat1
;
619 WORD SubstFormat
; /* = 2 */
623 }GSUB_SingleSubstFormat2
;
625 #ifdef HAVE_CARBON_CARBON_H
626 static char *find_cache_dir(void)
630 static char cached_path
[MAX_PATH
];
631 static const char *wine
= "/Wine", *fonts
= "/Fonts";
633 if(*cached_path
) return cached_path
;
635 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
638 WARN("can't create cached data folder\n");
641 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
644 WARN("can't create cached data path\n");
648 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
650 ERR("Could not create full path\n");
654 strcat(cached_path
, wine
);
656 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
658 WARN("Couldn't mkdir %s\n", cached_path
);
662 strcat(cached_path
, fonts
);
663 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
665 WARN("Couldn't mkdir %s\n", cached_path
);
672 /******************************************************************
675 * Extracts individual TrueType font files from a Mac suitcase font
676 * and saves them into the user's caches directory (see
678 * Returns a NULL terminated array of filenames.
680 * We do this because they are apps that try to read ttf files
681 * themselves and they don't like Mac suitcase files.
683 static char **expand_mac_font(const char *path
)
690 const char *filename
;
694 unsigned int size
, max_size
;
697 TRACE("path %s\n", path
);
699 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
702 WARN("failed to get ref\n");
706 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
709 TRACE("no data fork, so trying resource fork\n");
710 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
713 TRACE("unable to open resource fork\n");
720 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
723 CloseResFile(res_ref
);
727 out_dir
= find_cache_dir();
729 filename
= strrchr(path
, '/');
730 if(!filename
) filename
= path
;
733 /* output filename has the form out_dir/filename_%04x.ttf */
734 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
741 unsigned short *num_faces_ptr
, num_faces
, face
;
744 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
746 fond
= Get1IndResource(fond_res
, idx
);
748 TRACE("got fond resource %d\n", idx
);
751 fam_rec
= *(FamRec
**)fond
;
752 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
753 num_faces
= GET_BE_WORD(*num_faces_ptr
);
755 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
756 TRACE("num faces %04x\n", num_faces
);
757 for(face
= 0; face
< num_faces
; face
++, assoc
++)
760 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
761 unsigned short size
, font_id
;
764 size
= GET_BE_WORD(assoc
->fontSize
);
765 font_id
= GET_BE_WORD(assoc
->fontID
);
768 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
772 TRACE("trying to load sfnt id %04x\n", font_id
);
773 sfnt
= GetResource(sfnt_res
, font_id
);
776 TRACE("can't get sfnt resource %04x\n", font_id
);
780 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
785 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
787 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
788 if(fd
!= -1 || errno
== EEXIST
)
792 unsigned char *sfnt_data
;
795 sfnt_data
= *(unsigned char**)sfnt
;
796 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
800 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
803 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
805 ret
.array
[ret
.size
++] = output
;
809 WARN("unable to create %s\n", output
);
810 HeapFree(GetProcessHeap(), 0, output
);
813 ReleaseResource(sfnt
);
816 ReleaseResource(fond
);
819 CloseResFile(res_ref
);
824 #endif /* HAVE_CARBON_CARBON_H */
826 static inline BOOL
is_win9x(void)
828 return GetVersion() & 0x80000000;
831 This function builds an FT_Fixed from a double. It fails if the absolute
832 value of the float number is greater than 32768.
834 static inline FT_Fixed
FT_FixedFromFloat(double f
)
840 This function builds an FT_Fixed from a FIXED. It simply put f.value
841 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
843 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
845 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
849 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
854 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
855 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
857 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
858 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
860 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
862 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
864 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
868 file
= strrchr(face
->file
, '/');
873 if(!strcasecmp(file
, file_nameA
))
875 HeapFree(GetProcessHeap(), 0, file_nameA
);
880 HeapFree(GetProcessHeap(), 0, file_nameA
);
884 static Family
*find_family_from_name(const WCHAR
*name
)
888 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
890 if(!strcmpiW(family
->FamilyName
, name
))
897 static void DumpSubstList(void)
901 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
903 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
904 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
905 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
907 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
908 debugstr_w(psub
->to
.name
));
913 static LPWSTR
strdupW(LPCWSTR p
)
916 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
917 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
922 static LPSTR
strdupA(LPCSTR p
)
925 DWORD len
= (strlen(p
) + 1);
926 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
931 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
936 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
938 if(!strcmpiW(element
->from
.name
, from_name
) &&
939 (element
->from
.charset
== from_charset
||
940 element
->from
.charset
== -1))
947 #define ADD_FONT_SUBST_FORCE 1
949 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
951 FontSubst
*from_exist
, *to_exist
;
953 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
955 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
957 list_remove(&from_exist
->entry
);
958 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
959 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
960 HeapFree(GetProcessHeap(), 0, from_exist
);
966 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
970 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
971 subst
->to
.name
= strdupW(to_exist
->to
.name
);
974 list_add_tail(subst_list
, &subst
->entry
);
979 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
980 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
981 HeapFree(GetProcessHeap(), 0, subst
);
985 static void split_subst_info(NameCs
*nc
, LPSTR str
)
987 CHAR
*p
= strrchr(str
, ',');
992 nc
->charset
= strtol(p
+1, NULL
, 10);
995 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
996 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
997 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
1000 static void LoadSubstList(void)
1004 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1008 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1009 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1010 &hkey
) == ERROR_SUCCESS
) {
1012 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1013 &valuelen
, &datalen
, NULL
, NULL
);
1015 valuelen
++; /* returned value doesn't include room for '\0' */
1016 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1017 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1021 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1022 &dlen
) == ERROR_SUCCESS
) {
1023 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1025 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1026 split_subst_info(&psub
->from
, value
);
1027 split_subst_info(&psub
->to
, data
);
1029 /* Win 2000 doesn't allow mapping between different charsets
1030 or mapping of DEFAULT_CHARSET */
1031 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1032 psub
->to
.charset
== DEFAULT_CHARSET
) {
1033 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1034 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1035 HeapFree(GetProcessHeap(), 0, psub
);
1037 add_font_subst(&font_subst_list
, psub
, 0);
1039 /* reset dlen and vlen */
1043 HeapFree(GetProcessHeap(), 0, data
);
1044 HeapFree(GetProcessHeap(), 0, value
);
1050 /*****************************************************************
1051 * get_name_table_entry
1053 * Supply the platform, encoding, language and name ids in req
1054 * and if the name exists the function will fill in the string
1055 * and string_len members. The string is owned by FreeType so
1056 * don't free it. Returns TRUE if the name is found else FALSE.
1058 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1061 FT_UInt num_names
, name_index
;
1063 if(FT_IS_SFNT(ft_face
))
1065 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1067 for(name_index
= 0; name_index
< num_names
; name_index
++)
1069 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1071 if((name
.platform_id
== req
->platform_id
) &&
1072 (name
.encoding_id
== req
->encoding_id
) &&
1073 (name
.language_id
== req
->language_id
) &&
1074 (name
.name_id
== req
->name_id
))
1076 req
->string
= name
.string
;
1077 req
->string_len
= name
.string_len
;
1084 req
->string_len
= 0;
1088 static WCHAR
*get_familyname(FT_Face ft_face
)
1090 WCHAR
*family
= NULL
;
1093 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1094 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1095 name
.language_id
= GetUserDefaultLCID();
1096 name
.name_id
= TT_NAME_ID_FONT_FAMILY
;
1098 if(get_name_table_entry(ft_face
, &name
))
1102 /* String is not nul terminated and string_len is a byte length. */
1103 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1104 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1106 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1107 family
[i
] = GET_BE_WORD(*tmp
);
1110 TRACE("Got localised name %s\n", debugstr_w(family
));
1117 /*****************************************************************
1120 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1121 * of FreeType that don't export this function.
1124 static FT_Error
load_sfnt_table(FT_Face ft_face
, FT_ULong table
, FT_Long offset
, FT_Byte
*buf
, FT_ULong
*len
)
1129 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1130 if(pFT_Load_Sfnt_Table
)
1132 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, len
);
1134 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1135 else /* Do it the hard way */
1137 TT_Face tt_face
= (TT_Face
) ft_face
;
1138 SFNT_Interface
*sfnt
;
1139 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
1142 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
1146 /* A field was added in the middle of the structure in 2.1.x */
1147 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
1149 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, len
);
1157 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1158 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1159 "Please upgrade your freetype library.\n");
1162 err
= FT_Err_Unimplemented_Feature
;
1168 static inline int TestStyles(DWORD flags
, DWORD styles
)
1170 return (flags
& styles
) == styles
;
1173 static int StyleOrdering(Face
*face
)
1175 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1177 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1179 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1181 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1184 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1185 debugstr_w(face
->family
->FamilyName
),
1186 debugstr_w(face
->StyleName
),
1192 /* Add a style of face to a font family using an ordering of the list such
1193 that regular fonts come before bold and italic, and single styles come
1194 before compound styles. */
1195 static void AddFaceToFamily(Face
*face
, Family
*family
)
1199 LIST_FOR_EACH( entry
, &family
->faces
)
1201 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1202 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1204 list_add_before( entry
, &face
->entry
);
1207 #define ADDFONT_EXTERNAL_FONT 0x01
1208 #define ADDFONT_FORCE_BITMAP 0x02
1209 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1213 TT_Header
*pHeader
= NULL
;
1214 WCHAR
*english_family
, *localised_family
, *StyleW
;
1218 struct list
*family_elem_ptr
, *face_elem_ptr
;
1220 FT_Long face_index
= 0, num_faces
;
1221 #ifdef HAVE_FREETYPE_FTWINFNT_H
1222 FT_WinFNT_HeaderRec winfnt_header
;
1224 int i
, bitmap_num
, internal_leading
;
1227 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1228 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1230 #ifdef HAVE_CARBON_CARBON_H
1231 if(file
&& !fake_family
)
1233 char **mac_list
= expand_mac_font(file
);
1236 BOOL had_one
= FALSE
;
1238 for(cursor
= mac_list
; *cursor
; cursor
++)
1241 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1242 HeapFree(GetProcessHeap(), 0, *cursor
);
1244 HeapFree(GetProcessHeap(), 0, mac_list
);
1249 #endif /* HAVE_CARBON_CARBON_H */
1252 char *family_name
= fake_family
;
1256 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1257 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1260 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1261 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1265 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1269 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*/
1270 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1271 pFT_Done_Face(ft_face
);
1275 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1276 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1277 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1278 pFT_Done_Face(ft_face
);
1282 if(FT_IS_SFNT(ft_face
))
1284 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1285 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1286 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1288 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1289 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1290 pFT_Done_Face(ft_face
);
1294 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1295 we don't want to load these. */
1296 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1300 if(!load_sfnt_table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1302 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1303 pFT_Done_Face(ft_face
);
1309 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1310 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1311 pFT_Done_Face(ft_face
);
1315 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1317 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1318 pFT_Done_Face(ft_face
);
1324 localised_family
= get_familyname(ft_face
);
1325 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1327 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1328 HeapFree(GetProcessHeap(), 0, localised_family
);
1329 num_faces
= ft_face
->num_faces
;
1330 pFT_Done_Face(ft_face
);
1333 HeapFree(GetProcessHeap(), 0, localised_family
);
1337 family_name
= ft_face
->family_name
;
1341 My_FT_Bitmap_Size
*size
= NULL
;
1344 if(!FT_IS_SCALABLE(ft_face
))
1345 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1347 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1348 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1349 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1351 localised_family
= NULL
;
1353 localised_family
= get_familyname(ft_face
);
1354 if(localised_family
&& !strcmpiW(localised_family
, english_family
)) {
1355 HeapFree(GetProcessHeap(), 0, localised_family
);
1356 localised_family
= NULL
;
1361 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1362 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1363 if(!strcmpiW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1368 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1369 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1370 list_init(&family
->faces
);
1371 list_add_tail(&font_list
, &family
->entry
);
1373 if(localised_family
) {
1374 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1375 subst
->from
.name
= strdupW(english_family
);
1376 subst
->from
.charset
= -1;
1377 subst
->to
.name
= strdupW(localised_family
);
1378 subst
->to
.charset
= -1;
1379 add_font_subst(&font_subst_list
, subst
, 0);
1382 HeapFree(GetProcessHeap(), 0, localised_family
);
1383 HeapFree(GetProcessHeap(), 0, english_family
);
1385 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1386 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1387 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1389 internal_leading
= 0;
1390 memset(&fs
, 0, sizeof(fs
));
1392 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1394 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1395 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1396 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1397 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1398 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1399 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1400 if(pOS2
->version
== 0) {
1403 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1404 fs
.fsCsb
[0] |= FS_LATIN1
;
1406 fs
.fsCsb
[0] |= FS_SYMBOL
;
1409 #ifdef HAVE_FREETYPE_FTWINFNT_H
1410 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1412 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1413 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1414 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1416 internal_leading
= winfnt_header
.internal_leading
;
1420 face_elem_ptr
= list_head(&family
->faces
);
1421 while(face_elem_ptr
) {
1422 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1423 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1424 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1425 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1426 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1427 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1428 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1431 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1432 HeapFree(GetProcessHeap(), 0, StyleW
);
1433 pFT_Done_Face(ft_face
);
1436 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1437 TRACE("Original font is newer so skipping this one\n");
1438 HeapFree(GetProcessHeap(), 0, StyleW
);
1439 pFT_Done_Face(ft_face
);
1442 TRACE("Replacing original with this one\n");
1443 list_remove(&face
->entry
);
1444 HeapFree(GetProcessHeap(), 0, face
->file
);
1445 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1446 HeapFree(GetProcessHeap(), 0, face
);
1451 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1452 face
->cached_enum_data
= NULL
;
1453 face
->StyleName
= StyleW
;
1456 face
->file
= strdupA(file
);
1457 face
->font_data_ptr
= NULL
;
1458 face
->font_data_size
= 0;
1463 face
->font_data_ptr
= font_data_ptr
;
1464 face
->font_data_size
= font_data_size
;
1466 face
->face_index
= face_index
;
1468 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1469 face
->ntmFlags
|= NTM_ITALIC
;
1470 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1471 face
->ntmFlags
|= NTM_BOLD
;
1472 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1473 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1474 face
->family
= family
;
1475 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1477 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1479 if(FT_IS_SCALABLE(ft_face
)) {
1480 memset(&face
->size
, 0, sizeof(face
->size
));
1481 face
->scalable
= TRUE
;
1483 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1484 size
->height
, size
->width
, size
->size
>> 6,
1485 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1486 face
->size
.height
= size
->height
;
1487 face
->size
.width
= size
->width
;
1488 face
->size
.size
= size
->size
;
1489 face
->size
.x_ppem
= size
->x_ppem
;
1490 face
->size
.y_ppem
= size
->y_ppem
;
1491 face
->size
.internal_leading
= internal_leading
;
1492 face
->scalable
= FALSE
;
1495 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1497 if (pFT_Load_Sfnt_Table
&& !pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1499 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1500 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1503 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1504 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1505 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1506 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1509 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1510 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1511 switch(ft_face
->charmaps
[i
]->encoding
) {
1512 case FT_ENCODING_UNICODE
:
1513 case FT_ENCODING_APPLE_ROMAN
:
1514 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1516 case FT_ENCODING_MS_SYMBOL
:
1517 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1525 if (!(face
->fs
.fsCsb
[0] & FS_SYMBOL
))
1526 have_installed_roman_font
= TRUE
;
1528 AddFaceToFamily(face
, family
);
1530 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1532 num_faces
= ft_face
->num_faces
;
1533 pFT_Done_Face(ft_face
);
1534 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1535 debugstr_w(StyleW
));
1536 } while(num_faces
> ++face_index
);
1540 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1542 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1545 static void DumpFontList(void)
1549 struct list
*family_elem_ptr
, *face_elem_ptr
;
1551 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1552 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1553 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1554 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1555 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1556 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1558 TRACE(" %d", face
->size
.height
);
1565 /***********************************************************
1566 * The replacement list is a way to map an entire font
1567 * family onto another family. For example adding
1569 * [HKCU\Software\Wine\Fonts\Replacements]
1570 * "Wingdings"="Winedings"
1572 * would enumerate the Winedings font both as Winedings and
1573 * Wingdings. However if a real Wingdings font is present the
1574 * replacement does not take place.
1577 static void LoadReplaceList(void)
1580 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1585 struct list
*family_elem_ptr
, *face_elem_ptr
;
1588 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1589 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1591 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1592 &valuelen
, &datalen
, NULL
, NULL
);
1594 valuelen
++; /* returned value doesn't include room for '\0' */
1595 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1596 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1600 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1601 &dlen
) == ERROR_SUCCESS
) {
1602 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1603 /* "NewName"="Oldname" */
1604 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1606 /* Find the old family and hence all of the font files
1608 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1609 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1610 if(!strcmpiW(family
->FamilyName
, data
)) {
1611 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1612 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1613 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1614 debugstr_w(face
->StyleName
), familyA
);
1615 /* Now add a new entry with the new family name */
1616 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1621 /* reset dlen and vlen */
1625 HeapFree(GetProcessHeap(), 0, data
);
1626 HeapFree(GetProcessHeap(), 0, value
);
1631 /*************************************************************
1634 static BOOL
init_system_links(void)
1638 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1639 WCHAR
*value
, *data
;
1640 WCHAR
*entry
, *next
;
1641 SYSTEM_LINKS
*font_link
, *system_font_link
;
1642 CHILD_FONT
*child_font
;
1643 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1644 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1650 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1652 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1653 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1654 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1655 val_len
= max_val
+ 1;
1656 data_len
= max_data
;
1658 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1660 memset(&fs
, 0, sizeof(fs
));
1661 psub
= get_font_subst(&font_subst_list
, value
, -1);
1662 /* Don't store fonts that are only substitutes for other fonts */
1665 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
1668 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1669 font_link
->font_name
= strdupW(value
);
1670 list_init(&font_link
->links
);
1671 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1674 CHILD_FONT
*child_font
;
1676 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
1678 next
= entry
+ strlenW(entry
) + 1;
1680 face_name
= strchrW(entry
, ',');
1684 while(isspaceW(*face_name
))
1687 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1689 face_name
= psub
->to
.name
;
1691 face
= find_face_from_filename(entry
, face_name
);
1694 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1698 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1699 child_font
->face
= face
;
1700 child_font
->font
= NULL
;
1701 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1702 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1703 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1704 list_add_tail(&font_link
->links
, &child_font
->entry
);
1706 family
= find_family_from_name(font_link
->font_name
);
1709 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1711 face
->fs_links
= fs
;
1714 list_add_tail(&system_links
, &font_link
->entry
);
1716 val_len
= max_val
+ 1;
1717 data_len
= max_data
;
1720 HeapFree(GetProcessHeap(), 0, value
);
1721 HeapFree(GetProcessHeap(), 0, data
);
1725 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1728 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1729 system_font_link
->font_name
= strdupW(System
);
1730 list_init(&system_font_link
->links
);
1732 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1735 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1736 child_font
->face
= face
;
1737 child_font
->font
= NULL
;
1738 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
1739 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1741 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1743 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1745 CHILD_FONT
*font_link_entry
;
1746 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1748 CHILD_FONT
*new_child
;
1749 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1750 new_child
->face
= font_link_entry
->face
;
1751 new_child
->font
= NULL
;
1752 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1757 list_add_tail(&system_links
, &system_font_link
->entry
);
1761 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1764 struct dirent
*dent
;
1765 char path
[MAX_PATH
];
1767 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1769 dir
= opendir(dirname
);
1771 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1774 while((dent
= readdir(dir
)) != NULL
) {
1775 struct stat statbuf
;
1777 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1780 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1782 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1784 if(stat(path
, &statbuf
) == -1)
1786 WARN("Can't stat %s\n", debugstr_a(path
));
1789 if(S_ISDIR(statbuf
.st_mode
))
1790 ReadFontDir(path
, external_fonts
);
1792 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1798 static void load_fontconfig_fonts(void)
1800 #ifdef SONAME_LIBFONTCONFIG
1801 void *fc_handle
= NULL
;
1810 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1812 TRACE("Wine cannot find the fontconfig library (%s).\n",
1813 SONAME_LIBFONTCONFIG
);
1816 #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;}
1817 LOAD_FUNCPTR(FcConfigGetCurrent
);
1818 LOAD_FUNCPTR(FcFontList
);
1819 LOAD_FUNCPTR(FcFontSetDestroy
);
1820 LOAD_FUNCPTR(FcInit
);
1821 LOAD_FUNCPTR(FcObjectSetAdd
);
1822 LOAD_FUNCPTR(FcObjectSetCreate
);
1823 LOAD_FUNCPTR(FcObjectSetDestroy
);
1824 LOAD_FUNCPTR(FcPatternCreate
);
1825 LOAD_FUNCPTR(FcPatternDestroy
);
1826 LOAD_FUNCPTR(FcPatternGetBool
);
1827 LOAD_FUNCPTR(FcPatternGetString
);
1830 if(!pFcInit()) return;
1832 config
= pFcConfigGetCurrent();
1833 pat
= pFcPatternCreate();
1834 os
= pFcObjectSetCreate();
1835 pFcObjectSetAdd(os
, FC_FILE
);
1836 pFcObjectSetAdd(os
, FC_SCALABLE
);
1837 fontset
= pFcFontList(config
, pat
, os
);
1838 if(!fontset
) return;
1839 for(i
= 0; i
< fontset
->nfont
; i
++) {
1842 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1844 TRACE("fontconfig: %s\n", file
);
1846 /* We're just interested in OT/TT fonts for now, so this hack just
1847 picks up the scalable fonts without extensions .pf[ab] to save time
1848 loading every other font */
1850 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1852 TRACE("not scalable\n");
1856 len
= strlen( file
);
1857 if(len
< 4) continue;
1858 ext
= &file
[ len
- 3 ];
1859 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1860 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1862 pFcFontSetDestroy(fontset
);
1863 pFcObjectSetDestroy(os
);
1864 pFcPatternDestroy(pat
);
1870 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1873 const char *data_dir
= wine_get_data_dir();
1875 if (!data_dir
) data_dir
= wine_get_build_dir();
1882 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1884 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1886 strcpy(unix_name
, data_dir
);
1887 strcat(unix_name
, "/fonts/");
1889 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1891 EnterCriticalSection( &freetype_cs
);
1892 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1893 LeaveCriticalSection( &freetype_cs
);
1894 HeapFree(GetProcessHeap(), 0, unix_name
);
1899 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
1901 static const WCHAR slashW
[] = {'\\','\0'};
1903 WCHAR windowsdir
[MAX_PATH
];
1906 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1907 strcatW(windowsdir
, fontsW
);
1908 strcatW(windowsdir
, slashW
);
1909 strcatW(windowsdir
, file
);
1910 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
1911 EnterCriticalSection( &freetype_cs
);
1912 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1913 LeaveCriticalSection( &freetype_cs
);
1914 HeapFree(GetProcessHeap(), 0, unixname
);
1919 static void load_system_fonts(void)
1922 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1923 const WCHAR
* const *value
;
1925 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1928 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1929 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1930 strcatW(windowsdir
, fontsW
);
1931 for(value
= SystemFontValues
; *value
; value
++) {
1932 dlen
= sizeof(data
);
1933 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1937 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1938 if((unixname
= wine_get_unix_file_name(pathW
))) {
1939 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1940 HeapFree(GetProcessHeap(), 0, unixname
);
1943 load_font_from_data_dir(data
);
1950 /*************************************************************
1952 * This adds registry entries for any externally loaded fonts
1953 * (fonts from fontconfig or FontDirs). It also deletes entries
1954 * of no longer existing fonts.
1957 static void update_reg_entries(void)
1959 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
1964 struct list
*family_elem_ptr
, *face_elem_ptr
;
1966 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1967 static const WCHAR spaceW
[] = {' ', '\0'};
1970 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
1971 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
1972 ERR("Can't create Windows font reg key\n");
1976 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
1977 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
1978 ERR("Can't create Windows font reg key\n");
1982 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1983 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
1984 ERR("Can't create external font reg key\n");
1988 /* enumerate the fonts and add external ones to the two keys */
1990 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1991 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1992 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1993 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1994 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1995 if(!face
->external
) continue;
1997 if (!(face
->ntmFlags
& NTM_REGULAR
))
1998 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1999 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2000 strcpyW(valueW
, family
->FamilyName
);
2001 if(len
!= len_fam
) {
2002 strcatW(valueW
, spaceW
);
2003 strcatW(valueW
, face
->StyleName
);
2005 strcatW(valueW
, TrueType
);
2007 file
= wine_get_dos_file_name(face
->file
);
2009 len
= strlenW(file
) + 1;
2012 if((path
= strrchr(face
->file
, '/')) == NULL
)
2016 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2018 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2019 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2021 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2022 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2023 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2025 HeapFree(GetProcessHeap(), 0, file
);
2026 HeapFree(GetProcessHeap(), 0, valueW
);
2030 if(external_key
) RegCloseKey(external_key
);
2031 if(win9x_key
) RegCloseKey(win9x_key
);
2032 if(winnt_key
) RegCloseKey(winnt_key
);
2036 static void delete_external_font_keys(void)
2038 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2039 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2043 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2044 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2045 ERR("Can't create Windows font reg key\n");
2049 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2050 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2051 ERR("Can't create Windows font reg key\n");
2055 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2056 ERR("Can't create external font reg key\n");
2060 /* Delete all external fonts added last time */
2062 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2063 &valuelen
, &datalen
, NULL
, NULL
);
2064 valuelen
++; /* returned value doesn't include room for '\0' */
2065 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2066 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2068 dlen
= datalen
* sizeof(WCHAR
);
2071 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2072 &dlen
) == ERROR_SUCCESS
) {
2074 RegDeleteValueW(winnt_key
, valueW
);
2075 RegDeleteValueW(win9x_key
, valueW
);
2076 /* reset dlen and vlen */
2080 HeapFree(GetProcessHeap(), 0, data
);
2081 HeapFree(GetProcessHeap(), 0, valueW
);
2083 /* Delete the old external fonts key */
2084 RegCloseKey(external_key
);
2085 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2088 if(win9x_key
) RegCloseKey(win9x_key
);
2089 if(winnt_key
) RegCloseKey(winnt_key
);
2092 /*************************************************************
2093 * WineEngAddFontResourceEx
2096 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2102 if (ft_handle
) /* do it only if we have freetype up and running */
2107 FIXME("Ignoring flags %x\n", flags
);
2109 if((unixname
= wine_get_unix_file_name(file
)))
2111 EnterCriticalSection( &freetype_cs
);
2112 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2113 LeaveCriticalSection( &freetype_cs
);
2114 HeapFree(GetProcessHeap(), 0, unixname
);
2116 if (!ret
&& !strchrW(file
, '\\')) {
2117 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2118 ret
= load_font_from_winfonts_dir(file
);
2120 /* Try in datadir/fonts (or builddir/fonts),
2121 * needed for Magic the Gathering Online
2123 ret
= load_font_from_data_dir(file
);
2130 /*************************************************************
2131 * WineEngAddFontMemResourceEx
2134 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2138 if (ft_handle
) /* do it only if we have freetype up and running */
2140 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2142 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2143 memcpy(pFontCopy
, pbFont
, cbFont
);
2145 EnterCriticalSection( &freetype_cs
);
2146 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2147 LeaveCriticalSection( &freetype_cs
);
2151 TRACE("AddFontToList failed\n");
2152 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2155 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2156 * For now return something unique but quite random
2158 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2159 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2166 /*************************************************************
2167 * WineEngRemoveFontResourceEx
2170 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2177 static const struct nls_update_font_list
2179 UINT ansi_cp
, oem_cp
;
2180 const char *oem
, *fixed
, *system
;
2181 const char *courier
, *serif
, *small
, *sserif
;
2182 /* these are for font substitutes */
2183 const char *shelldlg
, *tmsrmn
;
2184 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2188 const char *from
, *to
;
2189 } arial_0
, courier_new_0
, times_new_roman_0
;
2190 } nls_update_font_list
[] =
2192 /* Latin 1 (United States) */
2193 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2194 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2195 "Tahoma","Times New Roman",
2196 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2199 /* Latin 1 (Multilingual) */
2200 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2201 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2202 "Tahoma","Times New Roman", /* FIXME unverified */
2203 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2206 /* Eastern Europe */
2207 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2208 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2209 "Tahoma","Times New Roman", /* FIXME unverified */
2210 "Fixedsys,238", "System,238",
2211 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2212 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2213 { "Arial CE,0", "Arial,238" },
2214 { "Courier New CE,0", "Courier New,238" },
2215 { "Times New Roman CE,0", "Times New Roman,238" }
2218 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2219 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2220 "Tahoma","Times New Roman", /* FIXME unverified */
2221 "Fixedsys,204", "System,204",
2222 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2223 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2224 { "Arial Cyr,0", "Arial,204" },
2225 { "Courier New Cyr,0", "Courier New,204" },
2226 { "Times New Roman Cyr,0", "Times New Roman,204" }
2229 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2230 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2231 "Tahoma","Times New Roman", /* FIXME unverified */
2232 "Fixedsys,161", "System,161",
2233 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2234 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2235 { "Arial Greek,0", "Arial,161" },
2236 { "Courier New Greek,0", "Courier New,161" },
2237 { "Times New Roman Greek,0", "Times New Roman,161" }
2240 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2241 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2242 "Tahoma","Times New Roman", /* FIXME unverified */
2243 "Fixedsys,162", "System,162",
2244 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2245 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2246 { "Arial Tur,0", "Arial,162" },
2247 { "Courier New Tur,0", "Courier New,162" },
2248 { "Times New Roman Tur,0", "Times New Roman,162" }
2251 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2252 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2253 "Tahoma","Times New Roman", /* FIXME unverified */
2254 "Fixedsys,177", "System,177",
2255 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2256 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2260 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2261 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2262 "Tahoma","Times New Roman", /* FIXME unverified */
2263 "Fixedsys,178", "System,178",
2264 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2265 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2269 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2270 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2271 "Tahoma","Times New Roman", /* FIXME unverified */
2272 "Fixedsys,186", "System,186",
2273 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2274 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2275 { "Arial Baltic,0", "Arial,186" },
2276 { "Courier New Baltic,0", "Courier New,186" },
2277 { "Times New Roman Baltic,0", "Times New Roman,186" }
2280 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2281 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2282 "Tahoma","Times New Roman", /* FIXME unverified */
2283 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2287 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2288 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2289 "Tahoma","Times New Roman", /* FIXME unverified */
2290 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2294 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2295 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2296 "MS UI Gothic","MS Serif",
2297 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2300 /* Chinese Simplified */
2301 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2302 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2303 "SimSun", "NSimSun",
2304 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2308 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2309 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2311 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2314 /* Chinese Traditional */
2315 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2316 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2317 "PMingLiU", "MingLiU",
2318 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2323 static const WCHAR
*font_links_list
[] =
2325 Lucida_Sans_Unicode
,
2326 Microsoft_Sans_Serif
,
2330 static const struct font_links_defaults_list
2332 /* Keyed off substitution for "MS Shell Dlg" */
2333 const WCHAR
*shelldlg
;
2334 /* Maximum of four substitutes, plus terminating NULL pointer */
2335 const WCHAR
*substitutes
[5];
2336 } font_links_defaults_list
[] =
2338 /* Non East-Asian */
2339 { Tahoma
, /* FIXME unverified ordering */
2340 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2342 /* Below lists are courtesy of
2343 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2347 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2349 /* Chinese Simplified */
2351 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2355 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2357 /* Chinese Traditional */
2359 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2363 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2365 return ( ansi_cp
== 932 /* CP932 for Japanese */
2366 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2367 || ansi_cp
== 949 /* CP949 for Korean */
2368 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2371 static inline HKEY
create_fonts_NT_registry_key(void)
2375 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2376 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2380 static inline HKEY
create_fonts_9x_registry_key(void)
2384 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2385 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2389 static inline HKEY
create_config_fonts_registry_key(void)
2393 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2394 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2398 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2400 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2401 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2402 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2403 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2406 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2409 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2411 RegDeleteValueA(hkey
, name
);
2414 static void update_font_info(void)
2416 char buf
[40], cpbuf
[40];
2419 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2422 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2425 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2426 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2427 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2428 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2429 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2431 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2432 if (is_dbcs_ansi_cp(ansi_cp
))
2433 use_default_fallback
= TRUE
;
2436 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2438 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2443 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2445 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2447 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2450 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2454 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2455 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2457 hkey
= create_config_fonts_registry_key();
2458 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2459 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2460 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2463 hkey
= create_fonts_NT_registry_key();
2464 add_font_list(hkey
, &nls_update_font_list
[i
]);
2467 hkey
= create_fonts_9x_registry_key();
2468 add_font_list(hkey
, &nls_update_font_list
[i
]);
2471 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2473 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2474 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2475 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2476 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2478 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2479 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2480 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2481 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2482 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2483 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2484 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2485 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2487 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2488 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2489 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2497 /* Delete the FontSubstitutes from other locales */
2498 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2500 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2501 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2502 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2508 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2510 /* Clear out system links */
2511 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, system_link
);
2514 static void populate_system_links(HKEY hkey
, const WCHAR
*name
, const WCHAR
*const *values
)
2524 WCHAR buff
[MAX_PATH
];
2528 static const WCHAR comma
[] = {',',0};
2530 RegDeleteValueW(hkey
, name
);
2535 for (i
= 0; values
[i
] != NULL
; i
++)
2538 if (!strcmpiW(name
,value
))
2540 psub
= get_font_subst(&font_subst_list
, value
, -1);
2542 value
= psub
->to
.name
;
2543 family
= find_family_from_name(value
);
2547 /* Use first extant filename for this Family */
2548 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2552 file
= strrchr(face
->file
, '/');
2561 fileLen
= MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, NULL
, 0);
2562 fileW
= HeapAlloc(GetProcessHeap(), 0, fileLen
* sizeof(WCHAR
));
2563 MultiByteToWideChar(CP_UNIXCP
, 0, file
, -1, fileW
, fileLen
);
2564 entryLen
= strlenW(fileW
) + 1 + strlenW(value
) + 1;
2565 if (sizeof(buff
)-(data
-buff
) < entryLen
+ 1)
2567 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name
));
2568 HeapFree(GetProcessHeap(), 0, fileW
);
2571 strcpyW(data
, fileW
);
2572 strcatW(data
, comma
);
2573 strcatW(data
, value
);
2575 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2576 HeapFree(GetProcessHeap(), 0, fileW
);
2582 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (BYTE
*)buff
, (data
-buff
) * sizeof(WCHAR
));
2584 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name
));
2586 TRACE("removed SystemLink for %s\n", debugstr_w(name
));
2589 static void update_system_links(void)
2597 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2599 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE
, system_link
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, &disposition
))
2601 if (disposition
== REG_OPENED_EXISTING_KEY
)
2603 TRACE("SystemLink key already exists, doing nothing\n");
2608 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2610 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2615 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2617 if (!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
))
2619 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2620 populate_system_links(hkey
, font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2622 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2623 populate_system_links(hkey
, psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2626 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2628 populate_system_links(hkey
, font_links_defaults_list
[i
].substitutes
[0], NULL
);
2633 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub
->to
.name
));
2635 WARN("failed to create SystemLink key\n");
2639 static BOOL
init_freetype(void)
2641 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2644 "Wine cannot find the FreeType font library. To enable Wine to\n"
2645 "use TrueType fonts please install a version of FreeType greater than\n"
2646 "or equal to 2.0.5.\n"
2647 "http://www.freetype.org\n");
2651 #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;}
2653 LOAD_FUNCPTR(FT_Vector_Unit
)
2654 LOAD_FUNCPTR(FT_Done_Face
)
2655 LOAD_FUNCPTR(FT_Get_Char_Index
)
2656 LOAD_FUNCPTR(FT_Get_Module
)
2657 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2658 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2659 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2660 LOAD_FUNCPTR(FT_Init_FreeType
)
2661 LOAD_FUNCPTR(FT_Load_Glyph
)
2662 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2663 #ifndef FT_MULFIX_INLINED
2664 LOAD_FUNCPTR(FT_MulFix
)
2666 LOAD_FUNCPTR(FT_New_Face
)
2667 LOAD_FUNCPTR(FT_New_Memory_Face
)
2668 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2669 LOAD_FUNCPTR(FT_Outline_Transform
)
2670 LOAD_FUNCPTR(FT_Outline_Translate
)
2671 LOAD_FUNCPTR(FT_Select_Charmap
)
2672 LOAD_FUNCPTR(FT_Set_Charmap
)
2673 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2674 LOAD_FUNCPTR(FT_Vector_Transform
)
2675 LOAD_FUNCPTR(FT_Render_Glyph
)
2678 /* Don't warn if these ones are missing */
2679 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
2680 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
2681 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
2682 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
2683 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2684 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2685 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2687 #ifdef HAVE_FREETYPE_FTWINFNT_H
2688 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
2690 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
2691 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2692 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2693 <= 2.0.3 has FT_Sqrt64 */
2697 if(pFT_Init_FreeType(&library
) != 0) {
2698 ERR("Can't init FreeType library\n");
2699 wine_dlclose(ft_handle
, NULL
, 0);
2703 FT_Version
.major
= FT_Version
.minor
= FT_Version
.patch
= -1;
2704 if (pFT_Library_Version
)
2705 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2707 if (FT_Version
.major
<=0)
2713 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2714 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2715 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2716 ((FT_Version
.patch
) & 0x0000ff);
2722 "Wine cannot find certain functions that it needs inside the FreeType\n"
2723 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2724 "FreeType to at least version 2.0.5.\n"
2725 "http://www.freetype.org\n");
2726 wine_dlclose(ft_handle
, NULL
, 0);
2731 /*************************************************************
2734 * Initialize FreeType library and create a list of available faces
2736 BOOL
WineEngInit(void)
2738 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
2739 static const WCHAR pathW
[] = {'P','a','t','h',0};
2741 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2742 WCHAR windowsdir
[MAX_PATH
];
2745 const char *data_dir
;
2749 /* update locale dependent font info in registry */
2752 if(!init_freetype()) return FALSE
;
2754 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2755 ERR("Failed to create font mutex\n");
2758 WaitForSingleObject(font_mutex
, INFINITE
);
2760 delete_external_font_keys();
2762 /* load the system bitmap fonts */
2763 load_system_fonts();
2765 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2766 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2767 strcatW(windowsdir
, fontsW
);
2768 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2770 ReadFontDir(unixname
, FALSE
);
2771 HeapFree(GetProcessHeap(), 0, unixname
);
2774 /* load the system truetype fonts */
2775 data_dir
= wine_get_data_dir();
2776 if (!data_dir
) data_dir
= wine_get_build_dir();
2777 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2778 strcpy(unixname
, data_dir
);
2779 strcat(unixname
, "/fonts/");
2780 ReadFontDir(unixname
, TRUE
);
2781 HeapFree(GetProcessHeap(), 0, unixname
);
2784 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2785 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2786 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2788 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2789 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2790 &hkey
) == ERROR_SUCCESS
) {
2791 LPWSTR data
, valueW
;
2792 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2793 &valuelen
, &datalen
, NULL
, NULL
);
2795 valuelen
++; /* returned value doesn't include room for '\0' */
2796 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2797 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2800 dlen
= datalen
* sizeof(WCHAR
);
2802 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
2803 &dlen
) == ERROR_SUCCESS
) {
2804 if(data
[0] && (data
[1] == ':'))
2806 if((unixname
= wine_get_unix_file_name(data
)))
2808 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2809 HeapFree(GetProcessHeap(), 0, unixname
);
2812 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
2814 WCHAR pathW
[MAX_PATH
];
2815 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2818 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2819 if((unixname
= wine_get_unix_file_name(pathW
)))
2821 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2822 HeapFree(GetProcessHeap(), 0, unixname
);
2825 load_font_from_data_dir(data
);
2827 /* reset dlen and vlen */
2832 HeapFree(GetProcessHeap(), 0, data
);
2833 HeapFree(GetProcessHeap(), 0, valueW
);
2837 load_fontconfig_fonts();
2839 /* then look in any directories that we've specified in the config file */
2840 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2841 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2847 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2849 len
+= sizeof(WCHAR
);
2850 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2851 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2853 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2854 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2855 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2856 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2860 LPSTR next
= strchr( ptr
, ':' );
2861 if (next
) *next
++ = 0;
2862 ReadFontDir( ptr
, TRUE
);
2865 HeapFree( GetProcessHeap(), 0, valueA
);
2867 HeapFree( GetProcessHeap(), 0, valueW
);
2876 update_reg_entries();
2878 update_system_links();
2879 init_system_links();
2881 ReleaseMutex(font_mutex
);
2886 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2889 TT_HoriHeader
*pHori
;
2893 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2894 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2896 if(height
== 0) height
= 16;
2898 /* Calc. height of EM square:
2900 * For +ve lfHeight we have
2901 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2902 * Re-arranging gives:
2903 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2905 * For -ve lfHeight we have
2907 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2908 * with il = winAscent + winDescent - units_per_em]
2913 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2914 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2915 pHori
->Ascender
- pHori
->Descender
);
2917 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
2918 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2926 static struct font_mapping
*map_font_file( const char *name
)
2928 struct font_mapping
*mapping
;
2932 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2933 if (fstat( fd
, &st
) == -1) goto error
;
2935 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2937 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2939 mapping
->refcount
++;
2944 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2947 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2950 if (mapping
->data
== MAP_FAILED
)
2952 HeapFree( GetProcessHeap(), 0, mapping
);
2955 mapping
->refcount
= 1;
2956 mapping
->dev
= st
.st_dev
;
2957 mapping
->ino
= st
.st_ino
;
2958 mapping
->size
= st
.st_size
;
2959 list_add_tail( &mappings_list
, &mapping
->entry
);
2967 static void unmap_font_file( struct font_mapping
*mapping
)
2969 if (!--mapping
->refcount
)
2971 list_remove( &mapping
->entry
);
2972 munmap( mapping
->data
, mapping
->size
);
2973 HeapFree( GetProcessHeap(), 0, mapping
);
2977 static LONG
load_VDMX(GdiFont
*, LONG
);
2979 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
2986 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
2990 if (!(font
->mapping
= map_font_file( face
->file
)))
2992 WARN("failed to map %s\n", debugstr_a(face
->file
));
2995 data_ptr
= font
->mapping
->data
;
2996 data_size
= font
->mapping
->size
;
3000 data_ptr
= face
->font_data_ptr
;
3001 data_size
= face
->font_data_size
;
3004 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3006 ERR("FT_New_Face rets %d\n", err
);
3010 /* set it here, as load_VDMX needs it */
3011 font
->ft_face
= ft_face
;
3013 if(FT_IS_SCALABLE(ft_face
)) {
3014 /* load the VDMX table if we have one */
3015 font
->ppem
= load_VDMX(font
, height
);
3017 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3018 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3020 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3021 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3023 font
->ppem
= height
;
3024 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3025 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3031 static int get_nearest_charset(Face
*face
, int *cp
)
3033 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3034 a single face with the requested charset. The idea is to check if
3035 the selected font supports the current ANSI codepage, if it does
3036 return the corresponding charset, else return the first charset */
3039 int acp
= GetACP(), i
;
3043 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3044 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3045 return csi
.ciCharset
;
3047 for(i
= 0; i
< 32; i
++) {
3049 if(face
->fs
.fsCsb
[0] & fs0
) {
3050 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3052 return csi
.ciCharset
;
3055 FIXME("TCI failing on %x\n", fs0
);
3059 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3060 face
->fs
.fsCsb
[0], face
->file
);
3062 return DEFAULT_CHARSET
;
3065 static GdiFont
*alloc_font(void)
3067 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3069 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3070 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3072 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3073 ret
->total_kern_pairs
= (DWORD
)-1;
3074 ret
->kern_pairs
= NULL
;
3075 list_init(&ret
->hfontlist
);
3076 list_init(&ret
->child_fonts
);
3080 static void free_font(GdiFont
*font
)
3082 struct list
*cursor
, *cursor2
;
3085 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3087 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3088 struct list
*first_hfont
;
3089 HFONTLIST
*hfontlist
;
3090 list_remove(cursor
);
3093 first_hfont
= list_head(&child
->font
->hfontlist
);
3094 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3095 DeleteObject(hfontlist
->hfont
);
3096 HeapFree(GetProcessHeap(), 0, hfontlist
);
3097 free_font(child
->font
);
3099 HeapFree(GetProcessHeap(), 0, child
);
3102 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3103 if (font
->mapping
) unmap_font_file( font
->mapping
);
3104 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3105 HeapFree(GetProcessHeap(), 0, font
->potm
);
3106 HeapFree(GetProcessHeap(), 0, font
->name
);
3107 for (i
= 0; i
< font
->gmsize
; i
++)
3108 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3109 HeapFree(GetProcessHeap(), 0, font
->gm
);
3110 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3111 HeapFree(GetProcessHeap(), 0, font
);
3115 /*************************************************************
3118 * load the vdmx entry for the specified height
3121 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3122 ( ( (FT_ULong)_x4 << 24 ) | \
3123 ( (FT_ULong)_x3 << 16 ) | \
3124 ( (FT_ULong)_x2 << 8 ) | \
3127 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3142 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3146 BYTE devXRatio
, devYRatio
;
3147 USHORT numRecs
, numRatios
;
3148 DWORD result
, offset
= -1;
3152 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3154 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3157 /* FIXME: need the real device aspect ratio */
3161 numRecs
= GET_BE_WORD(hdr
[1]);
3162 numRatios
= GET_BE_WORD(hdr
[2]);
3164 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3165 for(i
= 0; i
< numRatios
; i
++) {
3168 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3169 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3172 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3174 if((ratio
.xRatio
== 0 &&
3175 ratio
.yStartRatio
== 0 &&
3176 ratio
.yEndRatio
== 0) ||
3177 (devXRatio
== ratio
.xRatio
&&
3178 devYRatio
>= ratio
.yStartRatio
&&
3179 devYRatio
<= ratio
.yEndRatio
))
3181 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3182 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3183 offset
= GET_BE_WORD(tmp
);
3189 FIXME("No suitable ratio found\n");
3193 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3195 BYTE startsz
, endsz
;
3198 recs
= GET_BE_WORD(group
.recs
);
3199 startsz
= group
.startsz
;
3200 endsz
= group
.endsz
;
3202 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3204 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3205 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3206 if(result
== GDI_ERROR
) {
3207 FIXME("Failed to retrieve vTable\n");
3212 for(i
= 0; i
< recs
; i
++) {
3213 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3214 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3215 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3217 if(yMax
+ -yMin
== height
) {
3220 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3223 if(yMax
+ -yMin
> height
) {
3226 goto end
; /* failed */
3228 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3229 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3230 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3231 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3237 TRACE("ppem not found for height %d\n", height
);
3241 if(ppem
< startsz
|| ppem
> endsz
)
3244 for(i
= 0; i
< recs
; i
++) {
3246 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
3248 if(yPelHeight
> ppem
)
3251 if(yPelHeight
== ppem
) {
3252 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3253 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3254 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
3260 HeapFree(GetProcessHeap(), 0, vTable
);
3266 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3268 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3269 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3270 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3271 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3272 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3275 static void calc_hash(FONT_DESC
*pfd
)
3277 DWORD hash
= 0, *ptr
, two_chars
;
3281 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3283 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3285 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3287 pwc
= (WCHAR
*)&two_chars
;
3289 *pwc
= toupperW(*pwc
);
3291 *pwc
= toupperW(*pwc
);
3295 hash
^= !pfd
->can_use_bitmap
;
3300 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3305 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3309 fd
.can_use_bitmap
= can_use_bitmap
;
3312 /* try the child list */
3313 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3314 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3315 if(!fontcmp(ret
, &fd
)) {
3316 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3317 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3318 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3319 if(hflist
->hfont
== hfont
)
3325 /* try the in-use list */
3326 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3327 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3328 if(!fontcmp(ret
, &fd
)) {
3329 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3330 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3331 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3332 if(hflist
->hfont
== hfont
)
3335 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3336 hflist
->hfont
= hfont
;
3337 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3342 /* then the unused list */
3343 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3344 while(font_elem_ptr
) {
3345 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3346 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3347 if(!fontcmp(ret
, &fd
)) {
3348 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3349 assert(list_empty(&ret
->hfontlist
));
3350 TRACE("Found %p in unused list\n", ret
);
3351 list_remove(&ret
->entry
);
3352 list_add_head(&gdi_font_list
, &ret
->entry
);
3353 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3354 hflist
->hfont
= hfont
;
3355 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3362 static void add_to_cache(GdiFont
*font
)
3364 static DWORD cache_num
= 1;
3366 font
->cache_num
= cache_num
++;
3367 list_add_head(&gdi_font_list
, &font
->entry
);
3370 /*************************************************************
3371 * create_child_font_list
3373 static BOOL
create_child_font_list(GdiFont
*font
)
3376 SYSTEM_LINKS
*font_link
;
3377 CHILD_FONT
*font_link_entry
, *new_child
;
3381 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3382 font_name
= psub
? psub
->to
.name
: font
->name
;
3383 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3385 if(!strcmpiW(font_link
->font_name
, font_name
))
3387 TRACE("found entry in system list\n");
3388 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3390 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3391 new_child
->face
= font_link_entry
->face
;
3392 new_child
->font
= NULL
;
3393 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3394 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3401 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3402 * Sans Serif. This is how asian windows get default fallbacks for fonts
3404 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3405 font
->charset
!= OEM_CHARSET
&&
3406 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3407 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3409 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3411 TRACE("found entry in default fallback list\n");
3412 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3414 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3415 new_child
->face
= font_link_entry
->face
;
3416 new_child
->font
= NULL
;
3417 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3418 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3428 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3430 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3432 if (pFT_Set_Charmap
)
3435 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3437 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3439 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3441 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3443 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3444 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3446 switch (ft_face
->charmaps
[i
]->platform_id
)
3449 cmap_def
= ft_face
->charmaps
[i
];
3451 case 0: /* Apple Unicode */
3452 cmap0
= ft_face
->charmaps
[i
];
3454 case 1: /* Macintosh */
3455 cmap1
= ft_face
->charmaps
[i
];
3458 cmap2
= ft_face
->charmaps
[i
];
3460 case 3: /* Microsoft */
3461 cmap3
= ft_face
->charmaps
[i
];
3466 if (cmap3
) /* prefer Microsoft cmap table */
3467 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3469 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3471 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3473 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3475 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3477 return ft_err
== FT_Err_Ok
;
3480 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3483 /*************************************************************
3484 * WineEngCreateFontInstance
3487 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3490 Face
*face
, *best
, *best_bitmap
;
3491 Family
*family
, *last_resort_family
;
3492 struct list
*family_elem_ptr
, *face_elem_ptr
;
3493 INT height
, width
= 0;
3494 unsigned int score
= 0, new_score
;
3495 signed int diff
= 0, newdiff
;
3496 BOOL bd
, it
, can_use_bitmap
;
3501 FontSubst
*psub
= NULL
;
3503 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
3504 lf
.lfWidth
= abs(lf
.lfWidth
);
3506 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
3508 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3509 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3510 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3513 if(dc
->GraphicsMode
== GM_ADVANCED
)
3514 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3517 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3518 font scaling abilities. */
3519 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3520 dcmat
.eM21
= dcmat
.eM12
= 0;
3523 /* Try to avoid not necessary glyph transformations */
3524 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3526 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3527 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3528 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3531 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3532 dcmat
.eM21
, dcmat
.eM22
);
3535 EnterCriticalSection( &freetype_cs
);
3537 /* check the cache first */
3538 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3539 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3540 LeaveCriticalSection( &freetype_cs
);
3544 TRACE("not in cache\n");
3545 if(list_empty(&font_list
)) /* No fonts installed */
3547 TRACE("No fonts installed\n");
3548 LeaveCriticalSection( &freetype_cs
);
3551 if(!have_installed_roman_font
)
3553 TRACE("No roman font installed\n");
3554 LeaveCriticalSection( &freetype_cs
);
3560 ret
->font_desc
.matrix
= dcmat
;
3561 ret
->font_desc
.lf
= lf
;
3562 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3563 calc_hash(&ret
->font_desc
);
3564 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3565 hflist
->hfont
= hfont
;
3566 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3568 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3569 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3570 original value lfCharSet. Note this is a special case for
3571 Symbol and doesn't happen at least for "Wingdings*" */
3573 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3574 lf
.lfCharSet
= SYMBOL_CHARSET
;
3576 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3577 switch(lf
.lfCharSet
) {
3578 case DEFAULT_CHARSET
:
3579 csi
.fs
.fsCsb
[0] = 0;
3582 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3583 csi
.fs
.fsCsb
[0] = 0;
3589 if(lf
.lfFaceName
[0] != '\0') {
3590 SYSTEM_LINKS
*font_link
;
3591 CHILD_FONT
*font_link_entry
;
3592 LPWSTR FaceName
= lf
.lfFaceName
;
3595 * Check for a leading '@' this signals that the font is being
3596 * requested in tategaki mode (vertical writing substitution) but
3597 * does not affect the fontface that is to be selected.
3599 if (lf
.lfFaceName
[0]=='@')
3600 FaceName
= &lf
.lfFaceName
[1];
3602 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3605 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
3606 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
3607 if (psub
->to
.charset
!= -1)
3608 lf
.lfCharSet
= psub
->to
.charset
;
3611 /* We want a match on name and charset or just name if
3612 charset was DEFAULT_CHARSET. If the latter then
3613 we fixup the returned charset later in get_nearest_charset
3614 where we'll either use the charset of the current ansi codepage
3615 or if that's unavailable the first charset that the font supports.
3617 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3618 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3619 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
3620 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
3622 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3623 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3624 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3625 if(face
->scalable
|| can_use_bitmap
)
3632 * Try check the SystemLink list first for a replacement font.
3633 * We may find good replacements there.
3635 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3637 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
3638 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
3640 TRACE("found entry in system list\n");
3641 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3643 face
= font_link_entry
->face
;
3644 family
= face
->family
;
3645 if(csi
.fs
.fsCsb
[0] &
3646 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
3648 if(face
->scalable
|| can_use_bitmap
)
3656 psub
= NULL
; /* substitution is no more relevant */
3658 /* If requested charset was DEFAULT_CHARSET then try using charset
3659 corresponding to the current ansi codepage */
3660 if (!csi
.fs
.fsCsb
[0])
3663 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
3664 FIXME("TCI failed on codepage %d\n", acp
);
3665 csi
.fs
.fsCsb
[0] = 0;
3667 lf
.lfCharSet
= csi
.ciCharset
;
3670 /* Face families are in the top 4 bits of lfPitchAndFamily,
3671 so mask with 0xF0 before testing */
3673 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
3674 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
3675 strcpyW(lf
.lfFaceName
, defFixed
);
3676 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
3677 strcpyW(lf
.lfFaceName
, defSerif
);
3678 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
3679 strcpyW(lf
.lfFaceName
, defSans
);
3681 strcpyW(lf
.lfFaceName
, defSans
);
3682 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3683 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3684 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
3685 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3686 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3687 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3688 if(face
->scalable
|| can_use_bitmap
)
3694 last_resort_family
= NULL
;
3695 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3696 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3697 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3698 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3699 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
3702 if(can_use_bitmap
&& !last_resort_family
)
3703 last_resort_family
= family
;
3708 if(last_resort_family
) {
3709 family
= last_resort_family
;
3710 csi
.fs
.fsCsb
[0] = 0;
3714 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3715 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3716 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3717 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3718 if(face
->scalable
) {
3719 csi
.fs
.fsCsb
[0] = 0;
3720 WARN("just using first face for now\n");
3723 if(can_use_bitmap
&& !last_resort_family
)
3724 last_resort_family
= family
;
3727 if(!last_resort_family
) {
3728 FIXME("can't find a single appropriate font - bailing\n");
3730 LeaveCriticalSection( &freetype_cs
);
3734 WARN("could only find a bitmap font - this will probably look awful!\n");
3735 family
= last_resort_family
;
3736 csi
.fs
.fsCsb
[0] = 0;
3739 it
= lf
.lfItalic
? 1 : 0;
3740 bd
= lf
.lfWeight
> 550 ? 1 : 0;
3742 height
= lf
.lfHeight
;
3744 face
= best
= best_bitmap
= NULL
;
3745 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
3747 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
3751 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
3752 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
3753 new_score
= (italic
^ it
) + (bold
^ bd
);
3754 if(!best
|| new_score
<= score
)
3756 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3757 italic
, bold
, it
, bd
);
3760 if(best
->scalable
&& score
== 0) break;
3764 newdiff
= height
- (signed int)(best
->size
.height
);
3766 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
3767 if(!best_bitmap
|| new_score
< score
||
3768 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
3770 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
3773 if(score
== 0 && diff
== 0) break;
3780 face
= best
->scalable
? best
: best_bitmap
;
3781 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
3782 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
3786 if(csi
.fs
.fsCsb
[0]) {
3787 ret
->charset
= lf
.lfCharSet
;
3788 ret
->codepage
= csi
.ciACP
;
3791 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
3793 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
3794 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
3796 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
3798 if(!face
->scalable
) {
3799 /* Windows uses integer scaling factors for bitmap fonts */
3800 INT scale
, scaled_height
;
3802 /* FIXME: rotation of bitmap fonts is ignored */
3803 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
3805 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
3806 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3808 if (height
!= 0) height
= diff
;
3809 height
+= face
->size
.height
;
3811 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
3812 scaled_height
= scale
* face
->size
.height
;
3813 /* Only jump to the next height if the difference <= 25% original height */
3814 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
3815 /* The jump between unscaled and doubled is delayed by 1 */
3816 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
3817 ret
->scale_y
= scale
;
3819 width
= face
->size
.x_ppem
>> 6;
3820 height
= face
->size
.y_ppem
>> 6;
3824 TRACE("font scale y: %f\n", ret
->scale_y
);
3826 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
3831 LeaveCriticalSection( &freetype_cs
);
3835 ret
->ntmFlags
= face
->ntmFlags
;
3837 if (ret
->charset
== SYMBOL_CHARSET
&&
3838 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
3841 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
3845 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
3848 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
3849 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
3850 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
3851 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
3852 create_child_font_list(ret
);
3854 if (lf
.lfFaceName
[0]=='@') /* We need to try to load the GSUB table */
3856 int length
= WineEngGetFontData (ret
, GSUB_TAG
, 0, NULL
, 0);
3857 if (length
!= GDI_ERROR
)
3859 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
3860 WineEngGetFontData(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
3861 TRACE("Loaded GSUB table of %i bytes\n",length
);
3865 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
3868 LeaveCriticalSection( &freetype_cs
);
3872 static void dump_gdi_font_list(void)
3875 struct list
*elem_ptr
;
3877 TRACE("---------- gdiFont Cache ----------\n");
3878 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
3879 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3880 TRACE("gdiFont=%p %s %d\n",
3881 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3884 TRACE("---------- Unused gdiFont Cache ----------\n");
3885 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
3886 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
3887 TRACE("gdiFont=%p %s %d\n",
3888 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
3892 /*************************************************************
3893 * WineEngDestroyFontInstance
3895 * free the gdiFont associated with this handle
3898 BOOL
WineEngDestroyFontInstance(HFONT handle
)
3903 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3907 EnterCriticalSection( &freetype_cs
);
3909 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
3911 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
3912 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3913 if(hflist
->hfont
== handle
)
3915 TRACE("removing child font %p from child list\n", gdiFont
);
3916 list_remove(&gdiFont
->entry
);
3917 LeaveCriticalSection( &freetype_cs
);
3922 TRACE("destroying hfont=%p\n", handle
);
3924 dump_gdi_font_list();
3926 font_elem_ptr
= list_head(&gdi_font_list
);
3927 while(font_elem_ptr
) {
3928 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3929 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3931 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3932 while(hfontlist_elem_ptr
) {
3933 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3934 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3935 if(hflist
->hfont
== handle
) {
3936 list_remove(&hflist
->entry
);
3937 HeapFree(GetProcessHeap(), 0, hflist
);
3941 if(list_empty(&gdiFont
->hfontlist
)) {
3942 TRACE("Moving to Unused list\n");
3943 list_remove(&gdiFont
->entry
);
3944 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3949 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3950 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3951 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3952 while(font_elem_ptr
) {
3953 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3954 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3955 TRACE("freeing %p\n", gdiFont
);
3956 list_remove(&gdiFont
->entry
);
3959 LeaveCriticalSection( &freetype_cs
);
3963 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3964 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3969 if (face
->cached_enum_data
)
3972 *pelf
= face
->cached_enum_data
->elf
;
3973 *pntm
= face
->cached_enum_data
->ntm
;
3974 *ptype
= face
->cached_enum_data
->type
;
3978 font
= alloc_font();
3980 if(face
->scalable
) {
3981 height
= -2048; /* 2048 is the most common em size */
3984 height
= face
->size
.y_ppem
>> 6;
3985 width
= face
->size
.x_ppem
>> 6;
3987 font
->scale_y
= 1.0;
3989 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
3995 font
->name
= strdupW(face
->family
->FamilyName
);
3996 font
->ntmFlags
= face
->ntmFlags
;
3998 if (WineEngGetOutlineTextMetrics(font
, 0, NULL
))
4000 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4002 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4004 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4005 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4007 lstrcpynW(pelf
->elfFullName
,
4008 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
4010 lstrcpynW(pelf
->elfStyle
,
4011 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4016 WineEngGetTextMetrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4018 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4020 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4021 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4022 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4025 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4026 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4027 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4028 pntm
->ntmFontSig
= face
->fs
;
4030 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4032 pelf
->elfLogFont
.lfEscapement
= 0;
4033 pelf
->elfLogFont
.lfOrientation
= 0;
4034 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4035 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4036 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4037 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4038 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4039 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4040 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4041 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4042 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4043 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4044 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4047 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4048 *ptype
|= TRUETYPE_FONTTYPE
;
4049 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4050 *ptype
|= DEVICE_FONTTYPE
;
4051 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4052 *ptype
|= RASTER_FONTTYPE
;
4054 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4055 if (face
->cached_enum_data
)
4057 face
->cached_enum_data
->elf
= *pelf
;
4058 face
->cached_enum_data
->ntm
= *pntm
;
4059 face
->cached_enum_data
->type
= *ptype
;
4065 /*************************************************************
4069 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4073 struct list
*family_elem_ptr
, *face_elem_ptr
;
4075 NEWTEXTMETRICEXW ntm
;
4084 lf
.lfCharSet
= DEFAULT_CHARSET
;
4085 lf
.lfPitchAndFamily
= 0;
4086 lf
.lfFaceName
[0] = 0;
4090 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4093 EnterCriticalSection( &freetype_cs
);
4094 if(plf
->lfFaceName
[0]) {
4096 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4099 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4100 debugstr_w(psub
->to
.name
));
4102 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4106 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4107 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4108 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
4109 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4110 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4111 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4112 for(i
= 0; i
< 32; i
++) {
4113 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4114 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4115 strcpyW(elf
.elfScript
, OEM_DOSW
);
4116 i
= 32; /* break out of loop */
4117 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
4120 fs
.fsCsb
[0] = 1L << i
;
4122 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
4124 csi
.ciCharset
= DEFAULT_CHARSET
;
4125 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
4126 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
4127 elf
.elfLogFont
.lfCharSet
=
4128 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
4130 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
4132 FIXME("Unknown elfscript for bit %d\n", i
);
4135 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4136 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4137 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4138 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
4139 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4140 ntm
.ntmTm
.ntmFlags
);
4141 /* release section before callback (FIXME) */
4142 LeaveCriticalSection( &freetype_cs
);
4143 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
4144 EnterCriticalSection( &freetype_cs
);
4150 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4151 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4152 face_elem_ptr
= list_head(&family
->faces
);
4153 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4154 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4155 for(i
= 0; i
< 32; i
++) {
4156 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4157 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4158 strcpyW(elf
.elfScript
, OEM_DOSW
);
4159 i
= 32; /* break out of loop */
4160 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
4163 fs
.fsCsb
[0] = 1L << i
;
4165 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
4167 csi
.ciCharset
= DEFAULT_CHARSET
;
4168 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
4169 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
4170 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
4173 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
4175 FIXME("Unknown elfscript for bit %d\n", i
);
4178 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4179 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4180 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4181 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
4182 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4183 ntm
.ntmTm
.ntmFlags
);
4184 /* release section before callback (FIXME) */
4185 LeaveCriticalSection( &freetype_cs
);
4186 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return 0;
4187 EnterCriticalSection( &freetype_cs
);
4191 LeaveCriticalSection( &freetype_cs
);
4195 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4197 pt
->x
.value
= vec
->x
>> 6;
4198 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4199 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4200 pt
->y
.value
= vec
->y
>> 6;
4201 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4202 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4206 /***************************************************
4207 * According to the MSDN documentation on WideCharToMultiByte,
4208 * certain codepages cannot set the default_used parameter.
4209 * This returns TRUE if the codepage can set that parameter, false else
4210 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4212 static BOOL
codepage_sets_default_used(UINT codepage
)
4226 * GSUB Table handling functions
4229 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4231 const GSUB_CoverageFormat1
* cf1
;
4235 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4237 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4239 TRACE("Coverage Format 1, %i glyphs\n",count
);
4240 for (i
= 0; i
< count
; i
++)
4241 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4245 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4247 const GSUB_CoverageFormat2
* cf2
;
4250 cf2
= (GSUB_CoverageFormat2
*)cf1
;
4252 count
= GET_BE_WORD(cf2
->RangeCount
);
4253 TRACE("Coverage Format 2, %i ranges\n",count
);
4254 for (i
= 0; i
< count
; i
++)
4256 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4258 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4259 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4261 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4262 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4268 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4273 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4275 const GSUB_ScriptList
*script
;
4276 const GSUB_Script
*deflt
= NULL
;
4278 script
= (GSUB_ScriptList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->ScriptList
));
4280 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4281 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4283 const GSUB_Script
*scr
;
4286 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4287 scr
= (GSUB_Script
*)((LPBYTE
)script
+ offset
);
4289 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4291 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4297 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4301 const GSUB_LangSys
*Lang
;
4303 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4305 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4307 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4308 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4310 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4313 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4316 Lang
= (GSUB_LangSys
*)((LPBYTE
)script
+ offset
);
4322 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4325 const GSUB_FeatureList
*feature
;
4326 feature
= (GSUB_FeatureList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->FeatureList
));
4328 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4329 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4331 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4332 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4334 const GSUB_Feature
*feat
;
4335 feat
= (GSUB_Feature
*)((LPBYTE
)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4342 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4346 const GSUB_LookupList
*lookup
;
4347 lookup
= (GSUB_LookupList
*)((LPBYTE
)header
+ GET_BE_WORD(header
->LookupList
));
4349 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4350 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4352 const GSUB_LookupTable
*look
;
4353 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4354 look
= (GSUB_LookupTable
*)((LPBYTE
)lookup
+ offset
);
4355 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4356 if (GET_BE_WORD(look
->LookupType
) != 1)
4357 FIXME("We only handle SubType 1\n");
4362 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4364 const GSUB_SingleSubstFormat1
*ssf1
;
4365 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4366 ssf1
= (GSUB_SingleSubstFormat1
*)((LPBYTE
)look
+offset
);
4367 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4369 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4370 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4371 if (GSUB_is_glyph_covered((LPBYTE
)ssf1
+offset
, glyph
) != -1)
4373 TRACE(" Glyph 0x%x ->",glyph
);
4374 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4375 TRACE(" 0x%x\n",glyph
);
4380 const GSUB_SingleSubstFormat2
*ssf2
;
4384 ssf2
= (GSUB_SingleSubstFormat2
*)ssf1
;
4385 offset
= GET_BE_WORD(ssf1
->Coverage
);
4386 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4387 index
= GSUB_is_glyph_covered((LPBYTE
)ssf2
+offset
, glyph
);
4388 TRACE(" Coverage index %i\n",index
);
4391 TRACE(" Glyph is 0x%x ->",glyph
);
4392 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4393 TRACE("0x%x\n",glyph
);
4402 static const char* get_opentype_script(const GdiFont
*font
)
4405 * I am not sure if this is the correct way to generate our script tag
4408 switch (font
->charset
)
4410 case ANSI_CHARSET
: return "latn";
4411 case BALTIC_CHARSET
: return "latn"; /* ?? */
4412 case CHINESEBIG5_CHARSET
: return "hani";
4413 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4414 case GB2312_CHARSET
: return "hani";
4415 case GREEK_CHARSET
: return "grek";
4416 case HANGUL_CHARSET
: return "hang";
4417 case RUSSIAN_CHARSET
: return "cyrl";
4418 case SHIFTJIS_CHARSET
: return "kana";
4419 case TURKISH_CHARSET
: return "latn"; /* ?? */
4420 case VIETNAMESE_CHARSET
: return "latn";
4421 case JOHAB_CHARSET
: return "latn"; /* ?? */
4422 case ARABIC_CHARSET
: return "arab";
4423 case HEBREW_CHARSET
: return "hebr";
4424 case THAI_CHARSET
: return "thai";
4425 default: return "latn";
4429 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4431 const GSUB_Header
*header
;
4432 const GSUB_Script
*script
;
4433 const GSUB_LangSys
*language
;
4434 const GSUB_Feature
*feature
;
4436 if (!font
->GSUB_Table
)
4439 header
= font
->GSUB_Table
;
4441 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4444 TRACE("Script not found\n");
4447 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4450 TRACE("Language not found\n");
4453 feature
= GSUB_get_feature(header
, language
, "vrt2");
4455 feature
= GSUB_get_feature(header
, language
, "vert");
4458 TRACE("vrt2/vert feature not found\n");
4461 return GSUB_apply_feature(header
, feature
, glyph
);
4464 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
4468 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
4469 WCHAR wc
= (WCHAR
)glyph
;
4471 BOOL
*default_used_pointer
;
4474 default_used_pointer
= NULL
;
4475 default_used
= FALSE
;
4476 if (codepage_sets_default_used(font
->codepage
))
4477 default_used_pointer
= &default_used
;
4478 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
4481 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
4482 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
4483 return get_GSUB_vert_glyph(font
,ret
);
4486 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
&& glyph
< 0x100)
4487 glyph
= glyph
+ 0xf000;
4488 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
4489 return get_GSUB_vert_glyph(font
,glyphId
);
4492 /*************************************************************
4493 * WineEngGetGlyphIndices
4496 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4497 LPWORD pgi
, DWORD flags
)
4500 int default_char
= -1;
4502 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
4504 for(i
= 0; i
< count
; i
++)
4506 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
4509 if (default_char
== -1)
4511 if (FT_IS_SFNT(font
->ft_face
))
4513 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
4514 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
4519 WineEngGetTextMetrics(font
, &textm
);
4520 default_char
= textm
.tmDefaultChar
;
4523 pgi
[i
] = default_char
;
4529 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
4531 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
4532 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
4535 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
4537 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
4538 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
4541 /*************************************************************
4542 * WineEngGetGlyphOutline
4544 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4545 * except that the first parameter is the HWINEENGFONT of the font in
4546 * question rather than an HDC.
4549 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
4550 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4553 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
4554 FT_Face ft_face
= incoming_font
->ft_face
;
4555 GdiFont
*font
= incoming_font
;
4556 FT_UInt glyph_index
;
4557 DWORD width
, height
, pitch
, needed
= 0;
4558 FT_Bitmap ft_bitmap
;
4560 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
4562 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
4563 double widthRatio
= 1.0;
4564 FT_Matrix transMat
= identityMat
;
4565 FT_Matrix transMatUnrotated
;
4566 BOOL needsTransform
= FALSE
;
4567 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
4568 UINT original_index
;
4570 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
4571 buflen
, buf
, lpmat
);
4573 TRACE("font transform %f %f %f %f\n",
4574 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
4575 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
4578 EnterCriticalSection( &freetype_cs
);
4580 if(format
& GGO_GLYPH_INDEX
) {
4581 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
4582 original_index
= glyph
;
4583 format
&= ~GGO_GLYPH_INDEX
;
4585 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
4586 ft_face
= font
->ft_face
;
4587 original_index
= glyph_index
;
4590 if(format
& GGO_UNHINTED
) {
4591 load_flags
|= FT_LOAD_NO_HINTING
;
4592 format
&= ~GGO_UNHINTED
;
4595 /* tategaki never appears to happen to lower glyph index */
4596 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
4599 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
4600 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
4601 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
4602 font
->gmsize
* sizeof(GM
*));
4604 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
4605 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
4607 *lpgm
= FONT_GM(font
,original_index
)->gm
;
4608 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4609 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4610 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4611 LeaveCriticalSection( &freetype_cs
);
4612 return 1; /* FIXME */
4616 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
4617 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4619 /* Scaling factor */
4624 WineEngGetTextMetrics(font
, &tm
);
4626 widthRatio
= (double)font
->aveWidth
;
4627 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
4630 widthRatio
= font
->scale_y
;
4632 /* Scaling transform */
4633 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
4636 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
4639 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
4641 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
4642 needsTransform
= TRUE
;
4645 /* Slant transform */
4646 if (font
->fake_italic
) {
4649 slantMat
.xx
= (1 << 16);
4650 slantMat
.xy
= ((1 << 16) >> 2);
4652 slantMat
.yy
= (1 << 16);
4653 pFT_Matrix_Multiply(&slantMat
, &transMat
);
4654 needsTransform
= TRUE
;
4657 /* Rotation transform */
4658 transMatUnrotated
= transMat
;
4659 if(font
->orientation
&& !tategaki
) {
4660 FT_Matrix rotationMat
;
4662 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
4663 pFT_Vector_Unit(&vecAngle
, angle
);
4664 rotationMat
.xx
= vecAngle
.x
;
4665 rotationMat
.xy
= -vecAngle
.y
;
4666 rotationMat
.yx
= -rotationMat
.xy
;
4667 rotationMat
.yy
= rotationMat
.xx
;
4669 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
4670 needsTransform
= TRUE
;
4673 /* World transform */
4674 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
4677 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
4678 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
4679 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
4680 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
4681 pFT_Matrix_Multiply(&worldMat
, &transMat
);
4682 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
4683 needsTransform
= TRUE
;
4686 /* Extra transformation specified by caller */
4687 if (!is_identity_MAT2(lpmat
))
4690 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
4691 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
4692 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
4693 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
4694 pFT_Matrix_Multiply(&extraMat
, &transMat
);
4695 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
4696 needsTransform
= TRUE
;
4699 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4700 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4701 format
== GGO_GRAY8_BITMAP
))
4703 load_flags
|= FT_LOAD_NO_BITMAP
;
4706 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
4709 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
4710 LeaveCriticalSection( &freetype_cs
);
4714 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
4715 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
4717 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
) + 63) >> 6;
4719 bbx
= (right
- left
) >> 6;
4721 if(!needsTransform
) {
4722 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
4723 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
4724 ft_face
->glyph
->metrics
.height
) & -64;
4725 lpgm
->gmCellIncX
= adv
;
4726 lpgm
->gmCellIncY
= 0;
4730 for(xc
= 0; xc
< 2; xc
++) {
4731 for(yc
= 0; yc
< 2; yc
++) {
4732 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
4733 xc
* ft_face
->glyph
->metrics
.width
);
4734 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
4735 yc
* ft_face
->glyph
->metrics
.height
;
4736 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
4737 pFT_Vector_Transform(&vec
, &transMat
);
4738 if(xc
== 0 && yc
== 0) {
4739 left
= right
= vec
.x
;
4740 top
= bottom
= vec
.y
;
4742 if(vec
.x
< left
) left
= vec
.x
;
4743 else if(vec
.x
> right
) right
= vec
.x
;
4744 if(vec
.y
< bottom
) bottom
= vec
.y
;
4745 else if(vec
.y
> top
) top
= vec
.y
;
4750 right
= (right
+ 63) & -64;
4751 bottom
= bottom
& -64;
4752 top
= (top
+ 63) & -64;
4754 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
4755 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4757 pFT_Vector_Transform(&vec
, &transMat
);
4758 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
4759 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
4761 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
4763 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
4764 adv
= (vec
.x
+63) >> 6;
4766 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
4767 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
4768 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
4769 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
4771 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
4772 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
4773 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
4775 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
4776 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
4778 FONT_GM(font
,original_index
)->gm
= *lpgm
;
4779 FONT_GM(font
,original_index
)->adv
= adv
;
4780 FONT_GM(font
,original_index
)->lsb
= lsb
;
4781 FONT_GM(font
,original_index
)->bbx
= bbx
;
4782 FONT_GM(font
,original_index
)->init
= TRUE
;
4785 if(format
== GGO_METRICS
)
4787 LeaveCriticalSection( &freetype_cs
);
4788 return 1; /* FIXME */
4791 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
4792 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
4793 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
4794 format
== GGO_GRAY8_BITMAP
))
4796 TRACE("loaded a bitmap\n");
4797 LeaveCriticalSection( &freetype_cs
);
4803 width
= lpgm
->gmBlackBoxX
;
4804 height
= lpgm
->gmBlackBoxY
;
4805 pitch
= ((width
+ 31) >> 5) << 2;
4806 needed
= pitch
* height
;
4808 if(!buf
|| !buflen
) break;
4810 switch(ft_face
->glyph
->format
) {
4811 case ft_glyph_format_bitmap
:
4813 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4814 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
4815 INT h
= ft_face
->glyph
->bitmap
.rows
;
4817 memcpy(dst
, src
, w
);
4818 src
+= ft_face
->glyph
->bitmap
.pitch
;
4824 case ft_glyph_format_outline
:
4825 ft_bitmap
.width
= width
;
4826 ft_bitmap
.rows
= height
;
4827 ft_bitmap
.pitch
= pitch
;
4828 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
4829 ft_bitmap
.buffer
= buf
;
4832 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4834 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4836 /* Note: FreeType will only set 'black' bits for us. */
4837 memset(buf
, 0, needed
);
4838 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4842 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4843 LeaveCriticalSection( &freetype_cs
);
4848 case GGO_GRAY2_BITMAP
:
4849 case GGO_GRAY4_BITMAP
:
4850 case GGO_GRAY8_BITMAP
:
4851 case WINE_GGO_GRAY16_BITMAP
:
4853 unsigned int mult
, row
, col
;
4856 width
= lpgm
->gmBlackBoxX
;
4857 height
= lpgm
->gmBlackBoxY
;
4858 pitch
= (width
+ 3) / 4 * 4;
4859 needed
= pitch
* height
;
4861 if(!buf
|| !buflen
) break;
4863 switch(ft_face
->glyph
->format
) {
4864 case ft_glyph_format_bitmap
:
4866 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
4867 INT h
= ft_face
->glyph
->bitmap
.rows
;
4870 for(x
= 0; x
< pitch
; x
++)
4872 if(x
< ft_face
->glyph
->bitmap
.width
)
4873 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
4877 src
+= ft_face
->glyph
->bitmap
.pitch
;
4880 LeaveCriticalSection( &freetype_cs
);
4883 case ft_glyph_format_outline
:
4885 ft_bitmap
.width
= width
;
4886 ft_bitmap
.rows
= height
;
4887 ft_bitmap
.pitch
= pitch
;
4888 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
4889 ft_bitmap
.buffer
= buf
;
4892 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
4894 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
4896 memset(ft_bitmap
.buffer
, 0, buflen
);
4898 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
4900 if(format
== GGO_GRAY2_BITMAP
)
4902 else if(format
== GGO_GRAY4_BITMAP
)
4904 else if(format
== GGO_GRAY8_BITMAP
)
4906 else /* format == WINE_GGO_GRAY16_BITMAP */
4908 LeaveCriticalSection( &freetype_cs
);
4914 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
4915 LeaveCriticalSection( &freetype_cs
);
4920 for(row
= 0; row
< height
; row
++) {
4922 for(col
= 0; col
< width
; col
++, ptr
++) {
4923 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
4930 case WINE_GGO_HRGB_BITMAP
:
4931 case WINE_GGO_HBGR_BITMAP
:
4932 case WINE_GGO_VRGB_BITMAP
:
4933 case WINE_GGO_VBGR_BITMAP
:
4934 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4936 switch (ft_face
->glyph
->format
)
4938 case FT_GLYPH_FORMAT_BITMAP
:
4943 width
= lpgm
->gmBlackBoxX
;
4944 height
= lpgm
->gmBlackBoxY
;
4946 needed
= pitch
* height
;
4948 if (!buf
|| !buflen
) break;
4950 memset(buf
, 0, buflen
);
4952 src
= ft_face
->glyph
->bitmap
.buffer
;
4953 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
4957 for (x
= 0; x
< width
; x
++)
4959 if ( src
[x
/ 8] & (1 << ( (7 - (x
% 8)))) )
4960 ((unsigned int *)dst
)[x
] = ~0u;
4969 case FT_GLYPH_FORMAT_OUTLINE
:
4973 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
4974 INT x_shift
, y_shift
;
4976 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
4977 FT_Render_Mode render_mode
=
4978 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
4979 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
4981 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
4983 if ( render_mode
== FT_RENDER_MODE_LCD
)
4985 lpgm
->gmBlackBoxX
+= 2;
4986 lpgm
->gmptGlyphOrigin
.x
-= 1;
4990 lpgm
->gmBlackBoxY
+= 2;
4991 lpgm
->gmptGlyphOrigin
.y
+= 1;
4995 width
= lpgm
->gmBlackBoxX
;
4996 height
= lpgm
->gmBlackBoxY
;
4998 needed
= pitch
* height
;
5000 if (!buf
|| !buflen
) break;
5002 memset(buf
, 0, buflen
);
5004 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5006 if ( needsTransform
)
5007 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5009 if ( pFT_Library_SetLcdFilter
)
5010 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5011 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5013 src
= ft_face
->glyph
->bitmap
.buffer
;
5014 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5015 src_width
= ft_face
->glyph
->bitmap
.width
;
5016 src_height
= ft_face
->glyph
->bitmap
.rows
;
5018 if ( render_mode
== FT_RENDER_MODE_LCD
)
5026 rgb_interval
= src_pitch
;
5031 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5032 if ( x_shift
< 0 ) x_shift
= 0;
5033 if ( x_shift
+ (src_width
/ hmul
) > width
)
5034 x_shift
= width
- (src_width
/ hmul
);
5036 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5037 if ( y_shift
< 0 ) y_shift
= 0;
5038 if ( y_shift
+ (src_height
/ vmul
) > height
)
5039 y_shift
= height
- (src_height
/ vmul
);
5041 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5042 while ( src_height
)
5044 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5048 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5049 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5050 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5051 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5055 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5056 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5057 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5058 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5061 src
+= src_pitch
* vmul
;
5070 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5071 LeaveCriticalSection ( &freetype_cs
);
5078 LeaveCriticalSection( &freetype_cs
);
5084 int contour
, point
= 0, first_pt
;
5085 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5086 TTPOLYGONHEADER
*pph
;
5088 DWORD pph_start
, cpfx
, type
;
5090 if(buflen
== 0) buf
= NULL
;
5092 if (needsTransform
&& buf
) {
5093 pFT_Outline_Transform(outline
, &transMat
);
5096 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5098 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5101 pph
->dwType
= TT_POLYGON_TYPE
;
5102 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5104 needed
+= sizeof(*pph
);
5106 while(point
<= outline
->contours
[contour
]) {
5107 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5108 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5109 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5113 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5116 } while(point
<= outline
->contours
[contour
] &&
5117 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5118 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5119 /* At the end of a contour Windows adds the start point, but
5121 if(point
> outline
->contours
[contour
] &&
5122 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5124 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5126 } else if(point
<= outline
->contours
[contour
] &&
5127 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5128 /* add closing pt for bezier */
5130 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5138 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5141 pph
->cb
= needed
- pph_start
;
5147 /* Convert the quadratic Beziers to cubic Beziers.
5148 The parametric eqn for a cubic Bezier is, from PLRM:
5149 r(t) = at^3 + bt^2 + ct + r0
5150 with the control points:
5155 A quadratic Beizer has the form:
5156 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5158 So equating powers of t leads to:
5159 r1 = 2/3 p1 + 1/3 p0
5160 r2 = 2/3 p1 + 1/3 p2
5161 and of course r0 = p0, r3 = p2
5164 int contour
, point
= 0, first_pt
;
5165 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5166 TTPOLYGONHEADER
*pph
;
5168 DWORD pph_start
, cpfx
, type
;
5169 FT_Vector cubic_control
[4];
5170 if(buflen
== 0) buf
= NULL
;
5172 if (needsTransform
&& buf
) {
5173 pFT_Outline_Transform(outline
, &transMat
);
5176 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5178 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5181 pph
->dwType
= TT_POLYGON_TYPE
;
5182 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5184 needed
+= sizeof(*pph
);
5186 while(point
<= outline
->contours
[contour
]) {
5187 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5188 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5189 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5192 if(type
== TT_PRIM_LINE
) {
5194 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5198 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5201 /* FIXME: Possible optimization in endpoint calculation
5202 if there are two consecutive curves */
5203 cubic_control
[0] = outline
->points
[point
-1];
5204 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5205 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5206 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5207 cubic_control
[0].x
>>= 1;
5208 cubic_control
[0].y
>>= 1;
5210 if(point
+1 > outline
->contours
[contour
])
5211 cubic_control
[3] = outline
->points
[first_pt
];
5213 cubic_control
[3] = outline
->points
[point
+1];
5214 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5215 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5216 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5217 cubic_control
[3].x
>>= 1;
5218 cubic_control
[3].y
>>= 1;
5221 /* r1 = 1/3 p0 + 2/3 p1
5222 r2 = 1/3 p2 + 2/3 p1 */
5223 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5224 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5225 cubic_control
[2] = cubic_control
[1];
5226 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5227 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5228 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5229 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5231 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5232 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5233 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5238 } while(point
<= outline
->contours
[contour
] &&
5239 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5240 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5241 /* At the end of a contour Windows adds the start point,
5242 but only for Beziers and we've already done that.
5244 if(point
<= outline
->contours
[contour
] &&
5245 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5246 /* This is the closing pt of a bezier, but we've already
5247 added it, so just inc point and carry on */
5254 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5257 pph
->cb
= needed
- pph_start
;
5263 FIXME("Unsupported format %d\n", format
);
5264 LeaveCriticalSection( &freetype_cs
);
5267 LeaveCriticalSection( &freetype_cs
);
5271 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5273 FT_Face ft_face
= font
->ft_face
;
5274 #ifdef HAVE_FREETYPE_FTWINFNT_H
5275 FT_WinFNT_HeaderRec winfnt_header
;
5277 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5278 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5279 font
->potm
->otmSize
= size
;
5281 #define TM font->potm->otmTextMetrics
5282 #ifdef HAVE_FREETYPE_FTWINFNT_H
5283 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5285 TM
.tmHeight
= winfnt_header
.pixel_height
;
5286 TM
.tmAscent
= winfnt_header
.ascent
;
5287 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5288 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5289 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5290 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5291 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5292 TM
.tmWeight
= winfnt_header
.weight
;
5294 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5295 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5296 TM
.tmFirstChar
= winfnt_header
.first_char
;
5297 TM
.tmLastChar
= winfnt_header
.last_char
;
5298 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5299 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5300 TM
.tmItalic
= winfnt_header
.italic
;
5301 TM
.tmUnderlined
= font
->underline
;
5302 TM
.tmStruckOut
= font
->strikeout
;
5303 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5304 TM
.tmCharSet
= winfnt_header
.charset
;
5309 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5310 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5311 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5312 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5313 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5314 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5315 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5316 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5318 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5319 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5321 TM
.tmLastChar
= 255;
5322 TM
.tmDefaultChar
= 32;
5323 TM
.tmBreakChar
= 32;
5324 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5325 TM
.tmUnderlined
= font
->underline
;
5326 TM
.tmStruckOut
= font
->strikeout
;
5327 /* NB inverted meaning of TMPF_FIXED_PITCH */
5328 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5329 TM
.tmCharSet
= font
->charset
;
5337 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5339 double scale_x
, scale_y
;
5343 scale_x
= (double)font
->aveWidth
;
5344 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5347 scale_x
= font
->scale_y
;
5349 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5350 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5352 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5353 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5355 SCALE_Y(ptm
->tmHeight
);
5356 SCALE_Y(ptm
->tmAscent
);
5357 SCALE_Y(ptm
->tmDescent
);
5358 SCALE_Y(ptm
->tmInternalLeading
);
5359 SCALE_Y(ptm
->tmExternalLeading
);
5360 SCALE_Y(ptm
->tmOverhang
);
5362 SCALE_X(ptm
->tmAveCharWidth
);
5363 SCALE_X(ptm
->tmMaxCharWidth
);
5369 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5371 double scale_x
, scale_y
;
5375 scale_x
= (double)font
->aveWidth
;
5376 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5379 scale_x
= font
->scale_y
;
5381 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5382 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5384 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5386 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5387 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5389 SCALE_Y(potm
->otmAscent
);
5390 SCALE_Y(potm
->otmDescent
);
5391 SCALE_Y(potm
->otmLineGap
);
5392 SCALE_Y(potm
->otmsCapEmHeight
);
5393 SCALE_Y(potm
->otmsXHeight
);
5394 SCALE_Y(potm
->otmrcFontBox
.top
);
5395 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5396 SCALE_X(potm
->otmrcFontBox
.left
);
5397 SCALE_X(potm
->otmrcFontBox
.right
);
5398 SCALE_Y(potm
->otmMacAscent
);
5399 SCALE_Y(potm
->otmMacDescent
);
5400 SCALE_Y(potm
->otmMacLineGap
);
5401 SCALE_X(potm
->otmptSubscriptSize
.x
);
5402 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5403 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5404 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5405 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5406 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5407 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5408 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5409 SCALE_Y(potm
->otmsStrikeoutSize
);
5410 SCALE_Y(potm
->otmsStrikeoutPosition
);
5411 SCALE_Y(potm
->otmsUnderscoreSize
);
5412 SCALE_Y(potm
->otmsUnderscorePosition
);
5418 /*************************************************************
5419 * WineEngGetTextMetrics
5422 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5425 EnterCriticalSection( &freetype_cs
);
5427 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
5428 if(!get_bitmap_text_metrics(font
))
5430 LeaveCriticalSection( &freetype_cs
);
5434 /* Make sure that the font has sane width/height ratio */
5437 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
5439 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
5445 *ptm
= font
->potm
->otmTextMetrics
;
5446 scale_font_metrics(font
, ptm
);
5447 LeaveCriticalSection( &freetype_cs
);
5451 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5455 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5457 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
5463 /*************************************************************
5464 * WineEngGetOutlineTextMetrics
5467 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
5468 OUTLINETEXTMETRICW
*potm
)
5470 FT_Face ft_face
= font
->ft_face
;
5471 UINT needed
, lenfam
, lensty
, ret
;
5473 TT_HoriHeader
*pHori
;
5474 TT_Postscript
*pPost
;
5475 FT_Fixed x_scale
, y_scale
;
5476 WCHAR
*family_nameW
, *style_nameW
;
5477 static const WCHAR spaceW
[] = {' ', '\0'};
5479 INT ascent
, descent
;
5481 TRACE("font=%p\n", font
);
5483 if(!FT_IS_SCALABLE(ft_face
))
5487 EnterCriticalSection( &freetype_cs
);
5490 if(cbSize
>= font
->potm
->otmSize
)
5492 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5493 scale_outline_font_metrics(font
, potm
);
5495 LeaveCriticalSection( &freetype_cs
);
5496 return font
->potm
->otmSize
;
5500 needed
= sizeof(*potm
);
5502 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
5503 family_nameW
= strdupW(font
->name
);
5505 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
5507 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
5508 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
5509 style_nameW
, lensty
/sizeof(WCHAR
));
5511 /* These names should be read from the TT name table */
5513 /* length of otmpFamilyName */
5516 /* length of otmpFaceName */
5517 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
5518 needed
+= lenfam
; /* just the family name */
5520 needed
+= lenfam
+ lensty
; /* family + " " + style */
5523 /* length of otmpStyleName */
5526 /* length of otmpFullName */
5527 needed
+= lenfam
+ lensty
;
5530 x_scale
= ft_face
->size
->metrics
.x_scale
;
5531 y_scale
= ft_face
->size
->metrics
.y_scale
;
5533 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
5535 FIXME("Can't find OS/2 table - not TT font?\n");
5540 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
5542 FIXME("Can't find HHEA table - not TT font?\n");
5547 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
5549 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",
5550 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
5551 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
5552 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
5553 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
5554 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
5556 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
5557 font
->potm
->otmSize
= needed
;
5559 #define TM font->potm->otmTextMetrics
5561 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
5562 ascent
= pHori
->Ascender
;
5563 descent
= -pHori
->Descender
;
5565 ascent
= pOS2
->usWinAscent
;
5566 descent
= pOS2
->usWinDescent
;
5570 TM
.tmAscent
= font
->yMax
;
5571 TM
.tmDescent
= -font
->yMin
;
5572 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
5574 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
5575 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
5576 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
5577 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
5580 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5583 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5585 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
5586 ((ascent
+ descent
) -
5587 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
5589 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
5590 if (TM
.tmAveCharWidth
== 0) {
5591 TM
.tmAveCharWidth
= 1;
5593 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5594 TM
.tmWeight
= FW_REGULAR
;
5595 if (font
->fake_bold
)
5596 TM
.tmWeight
= FW_BOLD
;
5599 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
5601 if (pOS2
->usWeightClass
> FW_MEDIUM
)
5602 TM
.tmWeight
= pOS2
->usWeightClass
;
5604 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
5605 TM
.tmWeight
= pOS2
->usWeightClass
;
5608 TM
.tmDigitizedAspectX
= 300;
5609 TM
.tmDigitizedAspectY
= 300;
5610 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5611 * symbol range to 0 - f0ff
5614 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
5619 case 1257: /* Baltic */
5620 TM
.tmLastChar
= 0xf8fd;
5623 TM
.tmLastChar
= 0xf0ff;
5625 TM
.tmBreakChar
= 0x20;
5626 TM
.tmDefaultChar
= 0x1f;
5630 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
5631 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
5633 if(pOS2
->usFirstCharIndex
<= 1)
5634 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
5635 else if (pOS2
->usFirstCharIndex
> 0xff)
5636 TM
.tmBreakChar
= 0x20;
5638 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
5639 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
5641 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
5642 TM
.tmUnderlined
= font
->underline
;
5643 TM
.tmStruckOut
= font
->strikeout
;
5645 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5646 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
5647 (pOS2
->version
== 0xFFFFU
||
5648 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
5649 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
5651 TM
.tmPitchAndFamily
= 0;
5653 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
5655 case PAN_FAMILY_SCRIPT
:
5656 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
5659 case PAN_FAMILY_DECORATIVE
:
5660 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
5665 case PAN_FAMILY_TEXT_DISPLAY
:
5666 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
5667 /* which is clearly not what the panose spec says. */
5669 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
5670 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
5671 TM
.tmPitchAndFamily
= FF_MODERN
;
5674 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
5679 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
5682 case PAN_SERIF_COVE
:
5683 case PAN_SERIF_OBTUSE_COVE
:
5684 case PAN_SERIF_SQUARE_COVE
:
5685 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
5686 case PAN_SERIF_SQUARE
:
5687 case PAN_SERIF_THIN
:
5688 case PAN_SERIF_BONE
:
5689 case PAN_SERIF_EXAGGERATED
:
5690 case PAN_SERIF_TRIANGLE
:
5691 TM
.tmPitchAndFamily
|= FF_ROMAN
;
5694 case PAN_SERIF_NORMAL_SANS
:
5695 case PAN_SERIF_OBTUSE_SANS
:
5696 case PAN_SERIF_PERP_SANS
:
5697 case PAN_SERIF_FLARED
:
5698 case PAN_SERIF_ROUNDED
:
5699 TM
.tmPitchAndFamily
|= FF_SWISS
;
5706 if(FT_IS_SCALABLE(ft_face
))
5707 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
5709 if(FT_IS_SFNT(ft_face
))
5711 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
5712 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
5714 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
5717 TM
.tmCharSet
= font
->charset
;
5719 font
->potm
->otmFiller
= 0;
5720 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
5721 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
5722 font
->potm
->otmfsType
= pOS2
->fsType
;
5723 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
5724 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
5725 font
->potm
->otmItalicAngle
= 0; /* POST table */
5726 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
5727 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
5728 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
5729 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
5730 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
5731 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
5732 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
5733 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
5734 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
5735 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
5736 font
->potm
->otmMacAscent
= TM
.tmAscent
;
5737 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
5738 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
5739 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
5740 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
5741 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
5742 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
5743 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
5744 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
5745 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
5746 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
5747 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
5748 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
5749 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
5751 font
->potm
->otmsUnderscoreSize
= 0;
5752 font
->potm
->otmsUnderscorePosition
= 0;
5754 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
5755 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
5759 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5760 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
5761 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
5762 strcpyW((WCHAR
*)cp
, family_nameW
);
5764 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
5765 strcpyW((WCHAR
*)cp
, style_nameW
);
5767 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
5768 strcpyW((WCHAR
*)cp
, family_nameW
);
5769 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
5770 strcatW((WCHAR
*)cp
, spaceW
);
5771 strcatW((WCHAR
*)cp
, style_nameW
);
5772 cp
+= lenfam
+ lensty
;
5775 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
5776 strcpyW((WCHAR
*)cp
, family_nameW
);
5777 strcatW((WCHAR
*)cp
, spaceW
);
5778 strcatW((WCHAR
*)cp
, style_nameW
);
5781 if(potm
&& needed
<= cbSize
)
5783 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
5784 scale_outline_font_metrics(font
, potm
);
5788 HeapFree(GetProcessHeap(), 0, style_nameW
);
5789 HeapFree(GetProcessHeap(), 0, family_nameW
);
5791 LeaveCriticalSection( &freetype_cs
);
5795 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
5797 HFONTLIST
*hfontlist
;
5798 child
->font
= alloc_font();
5799 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
5800 if(!child
->font
->ft_face
)
5802 free_font(child
->font
);
5807 child
->font
->font_desc
= font
->font_desc
;
5808 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
5809 child
->font
->orientation
= font
->orientation
;
5810 child
->font
->scale_y
= font
->scale_y
;
5811 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
5812 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
5813 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
5814 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
5815 child
->font
->base_font
= font
;
5816 list_add_head(&child_font_list
, &child
->font
->entry
);
5817 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
5821 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
5824 CHILD_FONT
*child_font
;
5827 font
= font
->base_font
;
5829 *linked_font
= font
;
5831 if((*glyph
= get_glyph_index(font
, c
)))
5834 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
5836 if(!child_font
->font
)
5837 if(!load_child_font(font
, child_font
))
5840 if(!child_font
->font
->ft_face
)
5842 g
= get_glyph_index(child_font
->font
, c
);
5846 *linked_font
= child_font
->font
;
5853 /*************************************************************
5854 * WineEngGetCharWidth
5857 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5860 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5863 FT_UInt glyph_index
;
5864 GdiFont
*linked_font
;
5866 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5869 EnterCriticalSection( &freetype_cs
);
5870 for(c
= firstChar
; c
<= lastChar
; c
++) {
5871 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5872 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5873 &gm
, 0, NULL
, &identity
);
5874 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
5876 LeaveCriticalSection( &freetype_cs
);
5880 /*************************************************************
5881 * WineEngGetCharABCWidths
5884 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
5887 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5890 FT_UInt glyph_index
;
5891 GdiFont
*linked_font
;
5893 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
5895 if(!FT_IS_SCALABLE(font
->ft_face
))
5899 EnterCriticalSection( &freetype_cs
);
5901 for(c
= firstChar
; c
<= lastChar
; c
++) {
5902 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
5903 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5904 &gm
, 0, NULL
, &identity
);
5905 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
5906 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
5907 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
5908 FONT_GM(linked_font
,glyph_index
)->bbx
;
5910 LeaveCriticalSection( &freetype_cs
);
5914 /*************************************************************
5915 * WineEngGetCharABCWidthsI
5918 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
5921 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5924 FT_UInt glyph_index
;
5925 GdiFont
*linked_font
;
5927 if(!FT_HAS_HORIZONTAL(font
->ft_face
))
5931 EnterCriticalSection( &freetype_cs
);
5933 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
5935 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
5936 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5937 &gm
, 0, NULL
, &identity
);
5938 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
5939 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
5940 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
5941 - FONT_GM(linked_font
,c
)->bbx
;
5944 for(c
= 0; c
< count
; c
++) {
5945 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
5946 &gm
, 0, NULL
, &identity
);
5947 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
5948 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
5949 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
5950 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
5953 LeaveCriticalSection( &freetype_cs
);
5957 /*************************************************************
5958 * WineEngGetTextExtentExPoint
5961 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
5962 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
5964 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
5969 FT_UInt glyph_index
;
5970 GdiFont
*linked_font
;
5972 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
5976 EnterCriticalSection( &freetype_cs
);
5979 WineEngGetTextMetrics(font
, &tm
);
5980 size
->cy
= tm
.tmHeight
;
5982 for(idx
= 0; idx
< count
; idx
++) {
5983 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
5984 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
5985 &gm
, 0, NULL
, &identity
);
5986 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
5988 if (! pnfit
|| ext
<= max_ext
) {
5998 LeaveCriticalSection( &freetype_cs
);
5999 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6003 /*************************************************************
6004 * WineEngGetTextExtentExPointI
6007 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6008 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6010 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6016 TRACE("%p, %p, %d, %d, %p\n", font
, indices
, count
, max_ext
, size
);
6019 EnterCriticalSection( &freetype_cs
);
6022 WineEngGetTextMetrics(font
, &tm
);
6023 size
->cy
= tm
.tmHeight
;
6025 for(idx
= 0; idx
< count
; idx
++) {
6026 WineEngGetGlyphOutline(font
, indices
[idx
],
6027 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
6029 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
6031 if (! pnfit
|| ext
<= max_ext
) {
6041 LeaveCriticalSection( &freetype_cs
);
6042 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6046 /*************************************************************
6047 * WineEngGetFontData
6050 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6053 FT_Face ft_face
= font
->ft_face
;
6057 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6058 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6059 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6061 if(!FT_IS_SFNT(ft_face
))
6069 if(table
) { /* MS tags differ in endianness from FT ones */
6070 table
= table
>> 24 | table
<< 24 |
6071 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
6074 /* make sure value of len is the value freetype says it needs */
6077 FT_ULong needed
= 0;
6078 err
= load_sfnt_table(ft_face
, table
, offset
, NULL
, &needed
);
6079 if( !err
&& needed
< len
) len
= needed
;
6081 err
= load_sfnt_table(ft_face
, table
, offset
, buf
, &len
);
6084 TRACE("Can't find table %c%c%c%c\n",
6085 /* bytes were reversed */
6086 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
6087 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
6093 /*************************************************************
6094 * WineEngGetTextFace
6097 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6099 INT n
= strlenW(font
->name
) + 1;
6101 lstrcpynW(str
, font
->name
, count
);
6102 return min(count
, n
);
6107 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6109 if (fs
) *fs
= font
->fs
;
6110 return font
->charset
;
6113 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6115 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6116 struct list
*first_hfont
;
6120 EnterCriticalSection( &freetype_cs
);
6121 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6122 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6123 if(font
== linked_font
)
6124 *new_hfont
= dc
->hFont
;
6127 first_hfont
= list_head(&linked_font
->hfontlist
);
6128 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6130 LeaveCriticalSection( &freetype_cs
);
6134 /* Retrieve a list of supported Unicode ranges for a given font.
6135 * Can be called with NULL gs to calculate the buffer size. Returns
6136 * the number of ranges found.
6138 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6140 DWORD num_ranges
= 0;
6142 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6145 FT_ULong char_code
, char_code_prev
;
6148 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6150 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6151 face
->num_glyphs
, glyph_code
, char_code
);
6153 if (!glyph_code
) return 0;
6157 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6158 gs
->ranges
[0].cGlyphs
= 0;
6159 gs
->cGlyphsSupported
= 0;
6165 if (char_code
< char_code_prev
)
6167 ERR("expected increasing char code from FT_Get_Next_Char\n");
6170 if (char_code
- char_code_prev
> 1)
6175 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6176 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6177 gs
->cGlyphsSupported
++;
6182 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6183 gs
->cGlyphsSupported
++;
6185 char_code_prev
= char_code
;
6186 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6190 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6195 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6198 DWORD num_ranges
= get_font_unicode_ranges(font
->ft_face
, glyphset
);
6200 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6203 glyphset
->cbThis
= size
;
6204 glyphset
->cRanges
= num_ranges
;
6209 /*************************************************************
6212 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6216 EnterCriticalSection( &freetype_cs
);
6217 ret
= !list_empty(&font
->child_fonts
);
6218 LeaveCriticalSection( &freetype_cs
);
6222 static BOOL
is_hinting_enabled(void)
6224 /* Use the >= 2.2.0 function if available */
6225 if(pFT_Get_TrueType_Engine_Type
)
6227 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6228 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6230 #ifdef FT_DRIVER_HAS_HINTER
6235 /* otherwise if we've been compiled with < 2.2.0 headers
6236 use the internal macro */
6237 mod
= pFT_Get_Module(library
, "truetype");
6238 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6246 static BOOL
is_subpixel_rendering_enabled( void )
6248 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6249 return pFT_Library_SetLcdFilter
&&
6250 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6256 /*************************************************************************
6257 * GetRasterizerCaps (GDI32.@)
6259 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6261 static int hinting
= -1;
6262 static int subpixel
= -1;
6266 hinting
= is_hinting_enabled();
6267 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6270 if ( subpixel
== -1 )
6272 subpixel
= is_subpixel_rendering_enabled();
6273 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6276 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6277 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6279 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6280 lprs
->nLanguageID
= 0;
6284 /*************************************************************
6285 * WineEngRealizationInfo
6287 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6289 FIXME("(%p, %p): stub!\n", font
, info
);
6292 if(FT_IS_SCALABLE(font
->ft_face
))
6295 info
->cache_num
= font
->cache_num
;
6296 info
->unknown2
= -1;
6300 /*************************************************************************
6301 * Kerning support for TrueType fonts
6303 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6305 struct TT_kern_table
6311 struct TT_kern_subtable
6320 USHORT horizontal
: 1;
6322 USHORT cross_stream
: 1;
6323 USHORT override
: 1;
6324 USHORT reserved1
: 4;
6330 struct TT_format0_kern_subtable
6334 USHORT entrySelector
;
6345 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6346 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6347 const USHORT
*glyph_to_char
,
6348 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6351 const struct TT_kern_pair
*tt_kern_pair
;
6353 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6355 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6357 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6358 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6359 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6361 if (!kern_pair
|| !cPairs
)
6364 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6366 nPairs
= min(nPairs
, cPairs
);
6368 for (i
= 0; i
< nPairs
; i
++)
6370 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
6371 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
6372 /* this algorithm appears to better match what Windows does */
6373 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
6374 if (kern_pair
->iKernAmount
< 0)
6376 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
6377 kern_pair
->iKernAmount
-= font
->ppem
;
6379 else if (kern_pair
->iKernAmount
> 0)
6381 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
6382 kern_pair
->iKernAmount
+= font
->ppem
;
6384 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
6386 TRACE("left %u right %u value %d\n",
6387 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
6391 TRACE("copied %u entries\n", nPairs
);
6395 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6399 const struct TT_kern_table
*tt_kern_table
;
6400 const struct TT_kern_subtable
*tt_kern_subtable
;
6402 USHORT
*glyph_to_char
;
6405 EnterCriticalSection( &freetype_cs
);
6406 if (font
->total_kern_pairs
!= (DWORD
)-1)
6408 if (cPairs
&& kern_pair
)
6410 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6411 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6412 LeaveCriticalSection( &freetype_cs
);
6415 LeaveCriticalSection( &freetype_cs
);
6416 return font
->total_kern_pairs
;
6419 font
->total_kern_pairs
= 0;
6421 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
6423 if (length
== GDI_ERROR
)
6425 TRACE("no kerning data in the font\n");
6426 LeaveCriticalSection( &freetype_cs
);
6430 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
6433 WARN("Out of memory\n");
6434 LeaveCriticalSection( &freetype_cs
);
6438 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
6440 /* build a glyph index to char code map */
6441 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
6444 WARN("Out of memory allocating a glyph index to char code map\n");
6445 HeapFree(GetProcessHeap(), 0, buf
);
6446 LeaveCriticalSection( &freetype_cs
);
6450 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
6456 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
6458 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6459 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
6463 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6465 /* FIXME: This doesn't match what Windows does: it does some fancy
6466 * things with duplicate glyph index to char code mappings, while
6467 * we just avoid overriding existing entries.
6469 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
6470 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
6472 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
6479 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
6480 for (n
= 0; n
<= 65535; n
++)
6481 glyph_to_char
[n
] = (USHORT
)n
;
6484 tt_kern_table
= buf
;
6485 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
6486 TRACE("version %u, nTables %u\n",
6487 GET_BE_WORD(tt_kern_table
->version
), nTables
);
6489 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
6491 for (i
= 0; i
< nTables
; i
++)
6493 struct TT_kern_subtable tt_kern_subtable_copy
;
6495 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
6496 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
6497 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
6499 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6500 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
6501 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
6503 /* According to the TrueType specification this is the only format
6504 * that will be properly interpreted by Windows and OS/2
6506 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
6508 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
6510 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6511 glyph_to_char
, NULL
, 0);
6512 font
->total_kern_pairs
+= new_chunk
;
6514 if (!font
->kern_pairs
)
6515 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
6516 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6518 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
6519 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
6521 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
6522 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
6525 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
6527 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
6530 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
6531 HeapFree(GetProcessHeap(), 0, buf
);
6533 if (cPairs
&& kern_pair
)
6535 cPairs
= min(cPairs
, font
->total_kern_pairs
);
6536 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
6537 LeaveCriticalSection( &freetype_cs
);
6540 LeaveCriticalSection( &freetype_cs
);
6541 return font
->total_kern_pairs
;
6544 #else /* HAVE_FREETYPE */
6546 /*************************************************************************/
6548 BOOL
WineEngInit(void)
6552 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
6556 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
6561 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6566 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
6567 LPWORD pgi
, DWORD flags
)
6572 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
6573 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
6576 ERR("called but we don't have FreeType\n");
6580 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6582 ERR("called but we don't have FreeType\n");
6586 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
6587 OUTLINETEXTMETRICW
*potm
)
6589 ERR("called but we don't have FreeType\n");
6593 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6596 ERR("called but we don't have FreeType\n");
6600 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
6603 ERR("called but we don't have FreeType\n");
6607 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
6610 ERR("called but we don't have FreeType\n");
6614 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
6615 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6617 ERR("called but we don't have FreeType\n");
6621 BOOL
WineEngGetTextExtentExPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
6622 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
6624 ERR("called but we don't have FreeType\n");
6628 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
6631 ERR("called but we don't have FreeType\n");
6635 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
6637 ERR("called but we don't have FreeType\n");
6641 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6647 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
6653 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
6659 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
6662 return DEFAULT_CHARSET
;
6665 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6670 DWORD
WineEngGetFontUnicodeRanges(GdiFont
*font
, LPGLYPHSET glyphset
)
6672 FIXME("(%p, %p): stub\n", font
, glyphset
);
6676 BOOL
WineEngFontIsLinked(GdiFont
*font
)
6681 /*************************************************************************
6682 * GetRasterizerCaps (GDI32.@)
6684 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6686 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6688 lprs
->nLanguageID
= 0;
6692 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
6694 ERR("called but we don't have FreeType\n");
6698 BOOL
WineEngRealizationInfo(GdiFont
*font
, realization_info_t
*info
)
6700 ERR("called but we don't have FreeType\n");
6704 #endif /* HAVE_FREETYPE */