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 */
80 #ifdef HAVE_FT2BUILD_H
82 #include FT_FREETYPE_H
85 #include FT_TRUETYPE_TABLES_H
86 #include FT_SFNT_NAMES_H
87 #include FT_TRUETYPE_IDS_H
89 #include FT_TRIGONOMETRY_H
91 #include FT_WINFONTS_H
92 #ifdef FT_LCD_FILTER_H
93 #include FT_LCD_FILTER_H
95 #endif /* HAVE_FT2BUILD_H */
100 #include "winerror.h"
103 #include "gdi_private.h"
104 #include "wine/library.h"
105 #include "wine/unicode.h"
106 #include "wine/debug.h"
107 #include "wine/list.h"
109 #include "resource.h"
111 WINE_DEFAULT_DEBUG_CHANNEL(font
);
115 #ifndef HAVE_FT_TRUETYPEENGINETYPE
118 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
119 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
120 FT_TRUETYPE_ENGINE_TYPE_PATENTED
121 } FT_TrueTypeEngineType
;
124 static FT_Library library
= 0;
131 static FT_Version_t FT_Version
;
132 static DWORD FT_SimpleVersion
;
134 static void *ft_handle
= NULL
;
136 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
137 MAKE_FUNCPTR(FT_Done_Face
);
138 MAKE_FUNCPTR(FT_Get_Char_Index
);
139 MAKE_FUNCPTR(FT_Get_First_Char
);
140 MAKE_FUNCPTR(FT_Get_Next_Char
);
141 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
142 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
143 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
144 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
145 MAKE_FUNCPTR(FT_Init_FreeType
);
146 MAKE_FUNCPTR(FT_Library_Version
);
147 MAKE_FUNCPTR(FT_Load_Glyph
);
148 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
149 MAKE_FUNCPTR(FT_Matrix_Multiply
);
150 #ifdef FT_MULFIX_INLINED
151 #define pFT_MulFix FT_MULFIX_INLINED
153 MAKE_FUNCPTR(FT_MulFix
);
155 MAKE_FUNCPTR(FT_New_Face
);
156 MAKE_FUNCPTR(FT_New_Memory_Face
);
157 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
158 MAKE_FUNCPTR(FT_Outline_Get_CBox
);
159 MAKE_FUNCPTR(FT_Outline_Transform
);
160 MAKE_FUNCPTR(FT_Outline_Translate
);
161 MAKE_FUNCPTR(FT_Render_Glyph
);
162 MAKE_FUNCPTR(FT_Select_Charmap
);
163 MAKE_FUNCPTR(FT_Set_Charmap
);
164 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
165 MAKE_FUNCPTR(FT_Vector_Transform
);
166 MAKE_FUNCPTR(FT_Vector_Unit
);
167 static FT_Error (*pFT_Outline_Embolden
)(FT_Outline
*, FT_Pos
);
168 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
169 #ifdef FT_LCD_FILTER_H
170 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute
);
176 MAKE_FUNCPTR(FcFontList
);
177 MAKE_FUNCPTR(FcFontSetDestroy
);
178 MAKE_FUNCPTR(FcInit
);
179 MAKE_FUNCPTR(FcObjectSetAdd
);
180 MAKE_FUNCPTR(FcObjectSetCreate
);
181 MAKE_FUNCPTR(FcObjectSetDestroy
);
182 MAKE_FUNCPTR(FcPatternCreate
);
183 MAKE_FUNCPTR(FcPatternDestroy
);
184 MAKE_FUNCPTR(FcPatternGetBool
);
185 MAKE_FUNCPTR(FcPatternGetInteger
);
186 MAKE_FUNCPTR(FcPatternGetString
);
192 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
193 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
194 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
197 #ifndef ft_encoding_none
198 #define FT_ENCODING_NONE ft_encoding_none
200 #ifndef ft_encoding_ms_symbol
201 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
203 #ifndef ft_encoding_unicode
204 #define FT_ENCODING_UNICODE ft_encoding_unicode
206 #ifndef ft_encoding_apple_roman
207 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
210 #ifdef WORDS_BIGENDIAN
211 #define GET_BE_WORD(x) (x)
213 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
216 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
223 FT_Short internal_leading
;
226 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
227 So to let this compile on older versions of FreeType we'll define the
228 new structure here. */
230 FT_Short height
, width
;
231 FT_Pos size
, x_ppem
, y_ppem
;
237 NEWTEXTMETRICEXW ntm
;
241 typedef struct tagFace
{
243 unsigned int refcount
;
250 DWORD font_data_size
;
254 FT_Fixed font_version
;
256 Bitmap_Size size
; /* set if face is a bitmap */
257 DWORD flags
; /* ADDFONT flags */
258 struct tagFamily
*family
;
259 /* Cached data for Enum */
260 struct enum_data
*cached_enum_data
;
263 #define ADDFONT_EXTERNAL_FONT 0x01
264 #define ADDFONT_ALLOW_BITMAP 0x02
265 #define ADDFONT_ADD_TO_CACHE 0x04
266 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
267 #define ADDFONT_VERTICAL_FONT 0x10
268 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
270 typedef struct tagFamily
{
272 unsigned int refcount
;
276 struct list
*replacement
;
281 ABC abc
; /* metrics of the unrotated char */
297 typedef struct tagGdiFont GdiFont
;
299 #define FIRST_FONT_HANDLE 1
300 #define MAX_FONT_HANDLES 256
302 struct font_handle_entry
305 WORD generation
; /* generation count for reusing handle values */
308 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
309 static struct font_handle_entry
*next_free
;
310 static struct font_handle_entry
*next_unused
= font_handles
;
312 static inline DWORD
entry_to_handle( struct font_handle_entry
*entry
)
314 unsigned int idx
= entry
- font_handles
+ FIRST_FONT_HANDLE
;
315 return idx
| (entry
->generation
<< 16);
318 static inline struct font_handle_entry
*handle_entry( DWORD handle
)
320 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
322 if (idx
< MAX_FONT_HANDLES
)
324 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
325 return &font_handles
[idx
];
327 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
331 static DWORD
alloc_font_handle( void *obj
)
333 struct font_handle_entry
*entry
;
337 next_free
= entry
->obj
;
338 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
339 entry
= next_unused
++;
342 ERR( "out of realized font handles\n" );
346 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
347 return entry_to_handle( entry
);
350 static void free_font_handle( DWORD handle
)
352 struct font_handle_entry
*entry
;
354 if ((entry
= handle_entry( handle
)))
356 entry
->obj
= next_free
;
367 struct font_fileinfo
{
375 struct list unused_entry
;
376 unsigned int refcount
;
379 OUTLINETEXTMETRICW
*potm
;
380 DWORD total_kern_pairs
;
381 KERNINGPAIR
*kern_pairs
;
382 struct list child_fonts
;
384 /* the following members can be accessed without locking, they are never modified after creation */
386 struct font_mapping
*mapping
;
402 UINT ntmCellHeight
, ntmAvgWidth
;
406 const VOID
*vert_feature
;
409 struct font_fileinfo
*fileinfo
;
414 const WCHAR
*font_name
;
419 struct enum_charset_element
{
422 WCHAR name
[LF_FACESIZE
];
425 struct enum_charset_list
{
427 struct enum_charset_element element
[32];
430 #define GM_BLOCK_SIZE 128
431 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
433 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
434 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
435 static unsigned int unused_font_count
;
436 #define UNUSED_CACHE_SIZE 10
437 static struct list system_links
= LIST_INIT(system_links
);
439 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
441 static struct list font_list
= LIST_INIT(font_list
);
443 struct freetype_physdev
445 struct gdi_physdev dev
;
449 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
451 return (struct freetype_physdev
*)dev
;
454 static const struct gdi_dc_funcs freetype_funcs
;
456 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
457 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
458 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
460 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
461 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
462 'W','i','n','d','o','w','s','\\',
463 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
464 'F','o','n','t','s','\0'};
466 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
467 'W','i','n','d','o','w','s',' ','N','T','\\',
468 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
469 'F','o','n','t','s','\0'};
471 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
472 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
473 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
474 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
476 static const WCHAR
* const SystemFontValues
[] = {
483 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
484 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
486 /* Interesting and well-known (frequently-assumed!) font names */
487 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
488 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 };
489 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
490 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
491 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
492 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
493 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
494 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
496 static const WCHAR arial
[] = {'A','r','i','a','l',0};
497 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
498 static const WCHAR bitstream_vera_sans_mono
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
499 static const WCHAR bitstream_vera_serif
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
500 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
501 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
502 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
503 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
504 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
505 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
507 static const WCHAR
*default_serif_list
[] =
511 bitstream_vera_serif
,
515 static const WCHAR
*default_fixed_list
[] =
519 bitstream_vera_sans_mono
,
523 static const WCHAR
*default_sans_list
[] =
536 typedef struct tagFontSubst
{
542 /* Registry font cache key and value names */
543 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
544 'F','o','n','t','s',0};
545 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
546 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
547 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
548 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
549 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
550 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
551 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
552 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
553 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
554 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
555 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
556 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
557 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
558 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
559 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
572 static struct list mappings_list
= LIST_INIT( mappings_list
);
574 static UINT default_aa_flags
;
575 static HKEY hkey_font_cache
;
576 static BOOL antialias_fakes
= TRUE
;
578 static CRITICAL_SECTION freetype_cs
;
579 static CRITICAL_SECTION_DEBUG critsect_debug
=
582 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
583 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
585 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
587 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
589 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
590 static BOOL use_default_fallback
= FALSE
;
592 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
*vert
);
593 static BOOL
get_outline_text_metrics(GdiFont
*font
);
594 static BOOL
get_bitmap_text_metrics(GdiFont
*font
);
595 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
596 static void remove_face_from_cache( Face
*face
);
598 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
599 'W','i','n','d','o','w','s',' ','N','T','\\',
600 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
601 'S','y','s','t','e','m','L','i','n','k',0};
603 /****************************************
604 * Notes on .fon files
606 * The fonts System, FixedSys and Terminal are special. There are typically multiple
607 * versions installed for different resolutions and codepages. Windows stores which one to use
608 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
610 * FIXEDFON.FON FixedSys
612 * OEMFONT.FON Terminal
613 * LogPixels Current dpi set by the display control panel applet
614 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
615 * also has a LogPixels value that appears to mirror this)
617 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
618 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
619 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
620 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
621 * so that makes sense.
623 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
624 * to be mapped into the registry on Windows 2000 at least).
627 * ega80woa.fon=ega80850.fon
628 * ega40woa.fon=ega40850.fon
629 * cga80woa.fon=cga80850.fon
630 * cga40woa.fon=cga40850.fon
633 /* These are all structures needed for the GSUB table */
635 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
651 GSUB_ScriptRecord ScriptRecord
[1];
657 } GSUB_LangSysRecord
;
662 GSUB_LangSysRecord LangSysRecord
[1];
666 WORD LookupOrder
; /* Reserved */
667 WORD ReqFeatureIndex
;
669 WORD FeatureIndex
[1];
675 } GSUB_FeatureRecord
;
679 GSUB_FeatureRecord FeatureRecord
[1];
683 WORD FeatureParams
; /* Reserved */
685 WORD LookupListIndex
[1];
704 } GSUB_CoverageFormat1
;
709 WORD StartCoverageIndex
;
715 GSUB_RangeRecord RangeRecord
[1];
716 } GSUB_CoverageFormat2
;
719 WORD SubstFormat
; /* = 1 */
722 } GSUB_SingleSubstFormat1
;
725 WORD SubstFormat
; /* = 2 */
729 }GSUB_SingleSubstFormat2
;
731 #ifdef HAVE_CARBON_CARBON_H
732 static char *find_cache_dir(void)
736 static char cached_path
[MAX_PATH
];
737 static const char *wine
= "/Wine", *fonts
= "/Fonts";
739 if(*cached_path
) return cached_path
;
741 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
744 WARN("can't create cached data folder\n");
747 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
750 WARN("can't create cached data path\n");
754 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
756 ERR("Could not create full path\n");
760 strcat(cached_path
, wine
);
762 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
764 WARN("Couldn't mkdir %s\n", cached_path
);
768 strcat(cached_path
, fonts
);
769 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
771 WARN("Couldn't mkdir %s\n", cached_path
);
778 /******************************************************************
781 * Extracts individual TrueType font files from a Mac suitcase font
782 * and saves them into the user's caches directory (see
784 * Returns a NULL terminated array of filenames.
786 * We do this because they are apps that try to read ttf files
787 * themselves and they don't like Mac suitcase files.
789 static char **expand_mac_font(const char *path
)
796 const char *filename
;
800 unsigned int size
, max_size
;
803 TRACE("path %s\n", path
);
805 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
808 WARN("failed to get ref\n");
812 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
815 TRACE("no data fork, so trying resource fork\n");
816 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
819 TRACE("unable to open resource fork\n");
826 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
829 CloseResFile(res_ref
);
833 out_dir
= find_cache_dir();
835 filename
= strrchr(path
, '/');
836 if(!filename
) filename
= path
;
839 /* output filename has the form out_dir/filename_%04x.ttf */
840 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
847 unsigned short *num_faces_ptr
, num_faces
, face
;
850 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
852 fond
= Get1IndResource(fond_res
, idx
);
854 TRACE("got fond resource %d\n", idx
);
857 fam_rec
= *(FamRec
**)fond
;
858 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
859 num_faces
= GET_BE_WORD(*num_faces_ptr
);
861 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
862 TRACE("num faces %04x\n", num_faces
);
863 for(face
= 0; face
< num_faces
; face
++, assoc
++)
866 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
867 unsigned short size
, font_id
;
870 size
= GET_BE_WORD(assoc
->fontSize
);
871 font_id
= GET_BE_WORD(assoc
->fontID
);
874 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
878 TRACE("trying to load sfnt id %04x\n", font_id
);
879 sfnt
= GetResource(sfnt_res
, font_id
);
882 TRACE("can't get sfnt resource %04x\n", font_id
);
886 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
891 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
893 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
894 if(fd
!= -1 || errno
== EEXIST
)
898 unsigned char *sfnt_data
;
901 sfnt_data
= *(unsigned char**)sfnt
;
902 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
906 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
909 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
911 ret
.array
[ret
.size
++] = output
;
915 WARN("unable to create %s\n", output
);
916 HeapFree(GetProcessHeap(), 0, output
);
919 ReleaseResource(sfnt
);
922 ReleaseResource(fond
);
925 CloseResFile(res_ref
);
930 #endif /* HAVE_CARBON_CARBON_H */
932 static inline BOOL
is_win9x(void)
934 return GetVersion() & 0x80000000;
937 This function builds an FT_Fixed from a double. It fails if the absolute
938 value of the float number is greater than 32768.
940 static inline FT_Fixed
FT_FixedFromFloat(double f
)
946 This function builds an FT_Fixed from a FIXED. It simply put f.value
947 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
949 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
951 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
954 static BOOL
is_hinting_enabled(void)
956 static int enabled
= -1;
960 /* Use the >= 2.2.0 function if available */
961 if (pFT_Get_TrueType_Engine_Type
)
963 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
964 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
966 else enabled
= FALSE
;
967 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
972 static BOOL
is_subpixel_rendering_enabled( void )
974 #ifdef FT_LCD_FILTER_H
975 static int enabled
= -1;
978 enabled
= (pFT_Library_SetLcdFilter
&&
979 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
980 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
989 static const struct list
*get_face_list_from_family(const Family
*family
)
991 if (!list_empty(&family
->faces
))
992 return &family
->faces
;
994 return family
->replacement
;
997 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
1003 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
1005 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1007 const struct list
*face_list
;
1008 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
1010 face_list
= get_face_list_from_family(family
);
1011 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
1015 file
= strrchrW(face
->file
, '/');
1020 if(strcmpiW(file
, file_name
)) continue;
1028 static Family
*find_family_from_name(const WCHAR
*name
)
1032 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1034 if(!strcmpiW(family
->FamilyName
, name
))
1041 static Family
*find_family_from_any_name(const WCHAR
*name
)
1045 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1047 if(!strcmpiW(family
->FamilyName
, name
))
1049 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1056 static void DumpSubstList(void)
1060 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1062 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1063 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1064 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1066 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1067 debugstr_w(psub
->to
.name
));
1071 static LPWSTR
strdupW(LPCWSTR p
)
1074 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1075 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1076 memcpy(ret
, p
, len
);
1080 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1085 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1087 if(!strcmpiW(element
->from
.name
, from_name
) &&
1088 (element
->from
.charset
== from_charset
||
1089 element
->from
.charset
== -1))
1096 #define ADD_FONT_SUBST_FORCE 1
1098 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1100 FontSubst
*from_exist
, *to_exist
;
1102 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1104 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1106 list_remove(&from_exist
->entry
);
1107 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1108 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1109 HeapFree(GetProcessHeap(), 0, from_exist
);
1115 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1119 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1120 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1123 list_add_tail(subst_list
, &subst
->entry
);
1128 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1129 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1130 HeapFree(GetProcessHeap(), 0, subst
);
1134 static WCHAR
*towstr(UINT cp
, const char *str
)
1139 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1140 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1141 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1145 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1147 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1148 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1149 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1153 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1155 CHAR
*p
= strrchr(str
, ',');
1159 nc
->charset
= strtol(p
+1, NULL
, 10);
1162 nc
->name
= towstr(CP_ACP
, str
);
1165 static void LoadSubstList(void)
1169 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1173 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1174 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1175 &hkey
) == ERROR_SUCCESS
) {
1177 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1178 &valuelen
, &datalen
, NULL
, NULL
);
1180 valuelen
++; /* returned value doesn't include room for '\0' */
1181 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1182 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1186 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1187 &dlen
) == ERROR_SUCCESS
) {
1188 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1190 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1191 split_subst_info(&psub
->from
, value
);
1192 split_subst_info(&psub
->to
, data
);
1194 /* Win 2000 doesn't allow mapping between different charsets
1195 or mapping of DEFAULT_CHARSET */
1196 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1197 psub
->to
.charset
== DEFAULT_CHARSET
) {
1198 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1199 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1200 HeapFree(GetProcessHeap(), 0, psub
);
1202 add_font_subst(&font_subst_list
, psub
, 0);
1204 /* reset dlen and vlen */
1208 HeapFree(GetProcessHeap(), 0, data
);
1209 HeapFree(GetProcessHeap(), 0, value
);
1215 static const LANGID mac_langid_table
[] =
1217 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
1218 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
1219 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
1220 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
1221 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
1222 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
1223 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
1224 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
1225 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
1226 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
1227 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
1228 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
1229 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
1230 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
1231 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
1232 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
1233 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
1234 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
1235 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
1236 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1237 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
1238 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
1239 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
1240 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
1241 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
1242 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
1243 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
1244 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
1245 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
1246 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
1247 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
1248 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
1249 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
1250 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1251 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
1252 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
1253 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
1254 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
1255 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
1256 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
1257 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
1258 0, /* TT_MAC_LANGID_YIDDISH */
1259 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
1260 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
1261 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
1262 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
1263 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
1264 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
1265 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
1266 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
1267 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1268 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
1269 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
1270 0, /* TT_MAC_LANGID_MOLDAVIAN */
1271 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
1272 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
1273 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
1274 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
1275 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1276 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
1277 0, /* TT_MAC_LANGID_KURDISH */
1278 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
1279 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
1280 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
1281 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
1282 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
1283 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
1284 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
1285 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
1286 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
1287 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
1288 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
1289 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
1290 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
1291 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
1292 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
1293 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
1294 0, /* TT_MAC_LANGID_BURMESE */
1295 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
1296 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
1297 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
1298 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
1299 0, /* TT_MAC_LANGID_TAGALOG */
1300 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1301 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1302 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
1303 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
1304 0, /* TT_MAC_LANGID_GALLA */
1305 0, /* TT_MAC_LANGID_SOMALI */
1306 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
1307 0, /* TT_MAC_LANGID_RUANDA */
1308 0, /* TT_MAC_LANGID_RUNDI */
1309 0, /* TT_MAC_LANGID_CHEWA */
1310 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
1311 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
1312 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1313 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1314 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
1315 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
1316 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
1317 0, /* TT_MAC_LANGID_LATIN */
1318 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
1319 0, /* TT_MAC_LANGID_GUARANI */
1320 0, /* TT_MAC_LANGID_AYMARA */
1321 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
1322 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
1323 0, /* TT_MAC_LANGID_DZONGKHA */
1324 0, /* TT_MAC_LANGID_JAVANESE */
1325 0, /* TT_MAC_LANGID_SUNDANESE */
1326 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
1327 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
1328 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
1329 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
1330 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1331 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
1332 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
1333 0, /* TT_MAC_LANGID_TONGAN */
1334 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1335 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
1336 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1339 static inline WORD
get_mac_code_page( const FT_SfntName
*name
)
1341 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
1342 return 10000 + name
->encoding_id
;
1345 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
1350 switch (name
->platform_id
)
1352 case TT_PLATFORM_MICROSOFT
:
1353 res
+= 5; /* prefer the Microsoft name */
1354 switch (name
->encoding_id
)
1356 case TT_MS_ID_UNICODE_CS
:
1357 case TT_MS_ID_SYMBOL_CS
:
1358 name_lang
= name
->language_id
;
1364 case TT_PLATFORM_MACINTOSH
:
1365 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
1366 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1367 name_lang
= mac_langid_table
[name
->language_id
];
1369 case TT_PLATFORM_APPLE_UNICODE
:
1370 res
+= 2; /* prefer Unicode encodings */
1371 switch (name
->encoding_id
)
1373 case TT_APPLE_ID_DEFAULT
:
1374 case TT_APPLE_ID_ISO_10646
:
1375 case TT_APPLE_ID_UNICODE_2_0
:
1376 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1377 name_lang
= mac_langid_table
[name
->language_id
];
1386 if (name_lang
== lang
) res
+= 30;
1387 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
1388 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
1392 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
1398 switch (name
->platform_id
)
1400 case TT_PLATFORM_APPLE_UNICODE
:
1401 case TT_PLATFORM_MICROSOFT
:
1402 ret
= HeapAlloc( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
1403 for (i
= 0; i
< name
->string_len
/ 2; i
++)
1404 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
1407 case TT_PLATFORM_MACINTOSH
:
1408 codepage
= get_mac_code_page( name
);
1409 i
= MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, NULL
, 0 );
1410 ret
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(WCHAR
) );
1411 MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, ret
, i
);
1418 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
1421 FT_UInt num_names
, name_index
;
1422 int res
, best_lang
= 0, best_index
= -1;
1424 if (!FT_IS_SFNT(ft_face
)) return NULL
;
1426 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
1428 for (name_index
= 0; name_index
< num_names
; name_index
++)
1430 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
1431 if (name
.name_id
!= name_id
) continue;
1432 res
= match_name_table_language( &name
, language_id
);
1433 if (res
> best_lang
)
1436 best_index
= name_index
;
1440 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
1442 WCHAR
*ret
= copy_name_table_string( &name
);
1443 TRACE( "name %u found platform %u lang %04x %s\n",
1444 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
1450 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1452 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1453 if (f1
->scalable
) return TRUE
;
1454 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1455 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1458 static void release_family( Family
*family
)
1460 if (--family
->refcount
) return;
1461 assert( list_empty( &family
->faces
));
1462 list_remove( &family
->entry
);
1463 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1464 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1465 HeapFree( GetProcessHeap(), 0, family
);
1468 static void release_face( Face
*face
)
1470 if (--face
->refcount
) return;
1473 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1474 list_remove( &face
->entry
);
1475 release_family( face
->family
);
1477 HeapFree( GetProcessHeap(), 0, face
->file
);
1478 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1479 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1480 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1481 HeapFree( GetProcessHeap(), 0, face
);
1484 static inline int style_order(const Face
*face
)
1486 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1494 case NTM_BOLD
| NTM_ITALIC
:
1497 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1498 debugstr_w(face
->family
->FamilyName
),
1499 debugstr_w(face
->StyleName
),
1505 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1509 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1511 if (faces_equal( face
, cursor
))
1513 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1514 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1515 cursor
->font_version
, face
->font_version
);
1517 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1520 TRACE("Font %s already in list, refcount now %d\n",
1521 debugstr_w(face
->file
), cursor
->refcount
);
1524 if (face
->font_version
<= cursor
->font_version
)
1526 TRACE("Original font %s is newer so skipping %s\n",
1527 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1532 TRACE("Replacing original %s with %s\n",
1533 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1534 list_add_before( &cursor
->entry
, &face
->entry
);
1535 face
->family
= family
;
1538 release_face( cursor
);
1543 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1545 if (style_order( face
) < style_order( cursor
)) break;
1548 list_add_before( &cursor
->entry
, &face
->entry
);
1549 face
->family
= family
;
1555 /****************************************************************
1556 * NB This function stores the ptrs to the strings to save copying.
1557 * Don't free them after calling.
1559 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1561 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1562 family
->refcount
= 1;
1563 family
->FamilyName
= name
;
1564 family
->EnglishName
= english_name
;
1565 list_init( &family
->faces
);
1566 family
->replacement
= &family
->faces
;
1567 list_add_tail( &font_list
, &family
->entry
);
1572 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1574 DWORD type
, size
= sizeof(DWORD
);
1576 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1577 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1580 return ERROR_BAD_CONFIGURATION
;
1582 return ERROR_SUCCESS
;
1585 static inline LONG
reg_load_ftlong(HKEY hkey
, const WCHAR
*value
, FT_Long
*data
)
1588 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1593 static inline LONG
reg_load_ftshort(HKEY hkey
, const WCHAR
*value
, FT_Short
*data
)
1596 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1601 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1603 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1606 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1608 DWORD needed
, strike_index
= 0;
1611 /* If we have a File Name key then this is a real font, not just the parent
1612 key of a bunch of non-scalable strikes */
1613 needed
= buffer_size
;
1614 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1617 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1618 face
->cached_enum_data
= NULL
;
1619 face
->family
= NULL
;
1622 face
->file
= strdupW( buffer
);
1623 face
->StyleName
= strdupW(face_name
);
1625 needed
= buffer_size
;
1626 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1627 face
->FullName
= strdupW( buffer
);
1629 face
->FullName
= NULL
;
1631 reg_load_ftlong(hkey_face
, face_index_value
, &face
->face_index
);
1632 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1633 reg_load_ftlong(hkey_face
, face_version_value
, &face
->font_version
);
1634 reg_load_dword(hkey_face
, face_flags_value
, &face
->flags
);
1636 needed
= sizeof(face
->fs
);
1637 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1639 if(reg_load_ftshort(hkey_face
, face_height_value
, &face
->size
.height
) != ERROR_SUCCESS
)
1641 face
->scalable
= TRUE
;
1642 memset(&face
->size
, 0, sizeof(face
->size
));
1646 face
->scalable
= FALSE
;
1647 reg_load_ftshort(hkey_face
, face_width_value
, &face
->size
.width
);
1648 reg_load_ftlong(hkey_face
, face_size_value
, &face
->size
.size
);
1649 reg_load_ftlong(hkey_face
, face_x_ppem_value
, &face
->size
.x_ppem
);
1650 reg_load_ftlong(hkey_face
, face_y_ppem_value
, &face
->size
.y_ppem
);
1651 reg_load_ftshort(hkey_face
, face_internal_leading_value
, &face
->size
.internal_leading
);
1653 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1654 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1655 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1658 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1659 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1660 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1661 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1663 if (insert_face_in_family_list(face
, family
))
1664 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1666 release_face( face
);
1669 /* load bitmap strikes */
1671 needed
= buffer_size
;
1672 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1674 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1676 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1677 RegCloseKey(hkey_strike
);
1679 needed
= buffer_size
;
1683 /* move vertical fonts after their horizontal counterpart */
1684 /* assumes that font_list is already sorted by family name */
1685 static void reorder_vertical_fonts(void)
1687 Family
*family
, *next
, *vert_family
;
1688 struct list
*ptr
, *vptr
;
1689 struct list vertical_families
= LIST_INIT( vertical_families
);
1691 LIST_FOR_EACH_ENTRY_SAFE( family
, next
, &font_list
, Family
, entry
)
1693 if (family
->FamilyName
[0] != '@') continue;
1694 list_remove( &family
->entry
);
1695 list_add_tail( &vertical_families
, &family
->entry
);
1698 ptr
= list_head( &font_list
);
1699 vptr
= list_head( &vertical_families
);
1702 family
= LIST_ENTRY( ptr
, Family
, entry
);
1703 vert_family
= LIST_ENTRY( vptr
, Family
, entry
);
1704 if (strcmpiW( family
->FamilyName
, vert_family
->FamilyName
+ 1 ) > 0)
1706 list_remove( vptr
);
1707 list_add_before( ptr
, vptr
);
1708 vptr
= list_head( &vertical_families
);
1710 else ptr
= list_next( &font_list
, ptr
);
1712 list_move_tail( &font_list
, &vertical_families
);
1715 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1717 DWORD size
, family_index
= 0;
1722 size
= sizeof(buffer
);
1723 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1725 WCHAR
*english_family
= NULL
;
1726 WCHAR
*family_name
= strdupW( buffer
);
1727 DWORD face_index
= 0;
1729 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1730 TRACE("opened family key %s\n", debugstr_w(family_name
));
1731 size
= sizeof(buffer
);
1732 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1733 english_family
= strdupW( buffer
);
1735 family
= create_family(family_name
, english_family
);
1739 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1740 subst
->from
.name
= strdupW(english_family
);
1741 subst
->from
.charset
= -1;
1742 subst
->to
.name
= strdupW(family_name
);
1743 subst
->to
.charset
= -1;
1744 add_font_subst(&font_subst_list
, subst
, 0);
1747 size
= sizeof(buffer
);
1748 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1750 WCHAR
*face_name
= strdupW( buffer
);
1753 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1755 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1756 RegCloseKey(hkey_face
);
1758 HeapFree( GetProcessHeap(), 0, face_name
);
1759 size
= sizeof(buffer
);
1761 RegCloseKey(hkey_family
);
1762 release_family( family
);
1763 size
= sizeof(buffer
);
1766 reorder_vertical_fonts();
1769 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1772 HKEY hkey_wine_fonts
;
1774 /* We don't want to create the fonts key as volatile, so open this first */
1775 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1776 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1777 if(ret
!= ERROR_SUCCESS
)
1779 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1783 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1784 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1785 RegCloseKey(hkey_wine_fonts
);
1789 static void add_face_to_cache(Face
*face
)
1791 HKEY hkey_family
, hkey_face
;
1792 WCHAR
*face_key_name
;
1794 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1795 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1796 if(face
->family
->EnglishName
)
1797 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1798 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1801 face_key_name
= face
->StyleName
;
1804 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1805 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1806 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1808 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1811 HeapFree(GetProcessHeap(), 0, face_key_name
);
1813 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1814 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1816 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1817 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1819 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1820 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1821 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1822 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1824 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1828 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1829 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1830 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1831 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1832 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1833 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1835 RegCloseKey(hkey_face
);
1836 RegCloseKey(hkey_family
);
1839 static void remove_face_from_cache( Face
*face
)
1843 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1847 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1851 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1852 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1853 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1854 RegDeleteKeyW( hkey_family
, face_key_name
);
1855 HeapFree(GetProcessHeap(), 0, face_key_name
);
1857 RegCloseKey(hkey_family
);
1860 static WCHAR
*prepend_at(WCHAR
*family
)
1867 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1869 strcpyW(str
+ 1, family
);
1870 HeapFree(GetProcessHeap(), 0, family
);
1874 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1876 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
) );
1877 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1879 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1885 else if (!strcmpiW( *name
, *english
))
1887 HeapFree( GetProcessHeap(), 0, *english
);
1893 *name
= prepend_at( *name
);
1894 *english
= prepend_at( *english
);
1898 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1901 WCHAR
*name
, *english_name
;
1903 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1905 family
= find_family_from_name( name
);
1909 family
= create_family( name
, english_name
);
1912 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1913 subst
->from
.name
= strdupW( english_name
);
1914 subst
->from
.charset
= -1;
1915 subst
->to
.name
= strdupW( name
);
1916 subst
->to
.charset
= -1;
1917 add_font_subst( &font_subst_list
, subst
, 0 );
1922 HeapFree( GetProcessHeap(), 0, name
);
1923 HeapFree( GetProcessHeap(), 0, english_name
);
1930 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1932 FT_Fixed version
= 0;
1935 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1936 if (header
) version
= header
->Font_Revision
;
1941 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1944 FT_ULong table_size
= 0;
1946 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1947 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1948 if (flags
== 0) flags
= NTM_REGULAR
;
1950 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1951 flags
|= NTM_PS_OPENTYPE
;
1956 static inline void get_bitmap_size( FT_Face ft_face
, Bitmap_Size
*face_size
)
1958 My_FT_Bitmap_Size
*size
;
1959 FT_WinFNT_HeaderRec winfnt_header
;
1961 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1962 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1963 size
->height
, size
->width
, size
->size
>> 6,
1964 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1965 face_size
->height
= size
->height
;
1966 face_size
->width
= size
->width
;
1967 face_size
->size
= size
->size
;
1968 face_size
->x_ppem
= size
->x_ppem
;
1969 face_size
->y_ppem
= size
->y_ppem
;
1971 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
1972 face_size
->internal_leading
= winfnt_header
.internal_leading
;
1973 if (winfnt_header
.external_leading
> 0 &&
1974 (face_size
->height
==
1975 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
1976 face_size
->height
= winfnt_header
.pixel_height
;
1980 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1985 FT_WinFNT_HeaderRec winfnt_header
;
1988 memset( fs
, 0, sizeof(*fs
) );
1990 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1993 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1994 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1995 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1996 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1998 if (os2
->version
== 0)
2000 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
2001 fs
->fsCsb
[0] = FS_LATIN1
;
2003 fs
->fsCsb
[0] = FS_SYMBOL
;
2007 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
2008 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
2013 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
2015 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
2016 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
2017 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
2022 if (fs
->fsCsb
[0] == 0)
2024 /* let's see if we can find any interesting cmaps */
2025 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2027 switch (ft_face
->charmaps
[i
]->encoding
)
2029 case FT_ENCODING_UNICODE
:
2030 case FT_ENCODING_APPLE_ROMAN
:
2031 fs
->fsCsb
[0] |= FS_LATIN1
;
2033 case FT_ENCODING_MS_SYMBOL
:
2034 fs
->fsCsb
[0] |= FS_SYMBOL
;
2043 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2047 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
2050 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
2051 if (!face
->StyleName
) face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
2053 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
2054 if (flags
& ADDFONT_VERTICAL_FONT
)
2055 face
->FullName
= prepend_at( face
->FullName
);
2061 face
->file
= towstr( CP_UNIXCP
, file
);
2062 face
->font_data_ptr
= NULL
;
2063 face
->font_data_size
= 0;
2064 if (!stat( file
, &st
))
2066 face
->dev
= st
.st_dev
;
2067 face
->ino
= st
.st_ino
;
2073 face
->font_data_ptr
= font_data_ptr
;
2074 face
->font_data_size
= font_data_size
;
2077 face
->face_index
= face_index
;
2078 get_fontsig( ft_face
, &face
->fs
);
2079 face
->ntmFlags
= get_ntm_flags( ft_face
);
2080 face
->font_version
= get_font_version( ft_face
);
2082 if (FT_IS_SCALABLE( ft_face
))
2084 memset( &face
->size
, 0, sizeof(face
->size
) );
2085 face
->scalable
= TRUE
;
2089 get_bitmap_size( ft_face
, &face
->size
);
2090 face
->scalable
= FALSE
;
2093 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
2094 face
->flags
= flags
;
2095 face
->family
= NULL
;
2096 face
->cached_enum_data
= NULL
;
2098 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2099 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
2100 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
2101 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
2106 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2107 FT_Long face_index
, DWORD flags
)
2112 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
2113 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
2114 if (strlenW(family
->FamilyName
) >= LF_FACESIZE
)
2116 WARN("Ignoring %s because name is too long\n", debugstr_w(family
->FamilyName
));
2117 release_face( face
);
2118 release_family( family
);
2122 if (insert_face_in_family_list( face
, family
))
2124 if (flags
& ADDFONT_ADD_TO_CACHE
)
2125 add_face_to_cache( face
);
2127 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
2128 debugstr_w(face
->StyleName
));
2130 release_face( face
);
2131 release_family( family
);
2134 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2135 FT_Long face_index
, BOOL allow_bitmap
)
2143 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
2144 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
2148 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
2149 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
2154 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
2158 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2159 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
2161 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2165 if (!FT_IS_SFNT( ft_face
))
2167 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
2169 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2175 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
2176 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
2177 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
2179 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2180 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
2184 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2185 we don't want to load these. */
2186 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
2190 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
2192 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
2198 if (!ft_face
->family_name
|| !ft_face
->style_name
)
2200 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
2206 pFT_Done_Face( ft_face
);
2210 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
2213 FT_Long face_index
= 0, num_faces
;
2216 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2217 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
2219 #ifdef HAVE_CARBON_CARBON_H
2222 char **mac_list
= expand_mac_font(file
);
2225 BOOL had_one
= FALSE
;
2227 for(cursor
= mac_list
; *cursor
; cursor
++)
2230 AddFontToList(*cursor
, NULL
, 0, flags
);
2231 HeapFree(GetProcessHeap(), 0, *cursor
);
2233 HeapFree(GetProcessHeap(), 0, mac_list
);
2238 #endif /* HAVE_CARBON_CARBON_H */
2241 const DWORD FS_DBCS_MASK
= FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
;
2244 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
2245 if (!ft_face
) return 0;
2247 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
2249 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
2250 pFT_Done_Face(ft_face
);
2254 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
2257 get_fontsig(ft_face
, &fs
);
2258 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
2260 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
2261 flags
| ADDFONT_VERTICAL_FONT
);
2265 num_faces
= ft_face
->num_faces
;
2266 pFT_Done_Face(ft_face
);
2267 } while(num_faces
> ++face_index
);
2271 static int remove_font_resource( const char *file
, DWORD flags
)
2273 Family
*family
, *family_next
;
2274 Face
*face
, *face_next
;
2278 if (stat( file
, &st
) == -1) return 0;
2279 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2282 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2284 if (!face
->file
) continue;
2285 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2286 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2288 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2289 release_face( face
);
2293 release_family( family
);
2298 static void DumpFontList(void)
2303 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2304 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2305 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2306 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2308 TRACE(" %d", face
->size
.height
);
2314 static BOOL
map_font_family(const WCHAR
*orig
, const WCHAR
*repl
)
2316 Family
*family
= find_family_from_any_name(repl
);
2319 Family
*new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2320 if (new_family
!= NULL
)
2322 TRACE("mapping %s to %s\n", debugstr_w(repl
), debugstr_w(orig
));
2323 new_family
->FamilyName
= strdupW(orig
);
2324 new_family
->EnglishName
= NULL
;
2325 list_init(&new_family
->faces
);
2326 new_family
->replacement
= &family
->faces
;
2327 list_add_tail(&font_list
, &new_family
->entry
);
2331 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl
));
2335 /***********************************************************
2336 * The replacement list is a way to map an entire font
2337 * family onto another family. For example adding
2339 * [HKCU\Software\Wine\Fonts\Replacements]
2340 * "Wingdings"="Winedings"
2342 * would enumerate the Winedings font both as Winedings and
2343 * Wingdings. However if a real Wingdings font is present the
2344 * replacement does not take place.
2347 static void LoadReplaceList(void)
2350 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2354 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2355 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2357 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2358 &valuelen
, &datalen
, NULL
, NULL
);
2360 valuelen
++; /* returned value doesn't include room for '\0' */
2361 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2362 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2366 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
, &dlen
) == ERROR_SUCCESS
)
2368 /* "NewName"="Oldname" */
2369 if(!find_family_from_any_name(value
))
2371 if (type
== REG_MULTI_SZ
)
2373 WCHAR
*replace
= data
;
2376 if (map_font_family(value
, replace
))
2378 replace
+= strlenW(replace
) + 1;
2382 map_font_family(value
, data
);
2385 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2387 /* reset dlen and vlen */
2391 HeapFree(GetProcessHeap(), 0, data
);
2392 HeapFree(GetProcessHeap(), 0, value
);
2397 static const WCHAR
*font_links_list
[] =
2399 Lucida_Sans_Unicode
,
2400 Microsoft_Sans_Serif
,
2404 static const struct font_links_defaults_list
2406 /* Keyed off substitution for "MS Shell Dlg" */
2407 const WCHAR
*shelldlg
;
2408 /* Maximum of four substitutes, plus terminating NULL pointer */
2409 const WCHAR
*substitutes
[5];
2410 } font_links_defaults_list
[] =
2412 /* Non East-Asian */
2413 { Tahoma
, /* FIXME unverified ordering */
2414 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2416 /* Below lists are courtesy of
2417 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2421 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2423 /* Chinese Simplified */
2425 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2429 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2431 /* Chinese Traditional */
2433 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2438 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2440 SYSTEM_LINKS
*font_link
;
2442 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2444 if(!strcmpiW(font_link
->font_name
, name
))
2451 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2462 SYSTEM_LINKS
*font_link
;
2464 psub
= get_font_subst(&font_subst_list
, name
, -1);
2465 /* Don't store fonts that are only substitutes for other fonts */
2468 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2472 font_link
= find_font_link(name
);
2473 if (font_link
== NULL
)
2475 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2476 font_link
->font_name
= strdupW(name
);
2477 list_init(&font_link
->links
);
2478 list_add_tail(&system_links
, &font_link
->entry
);
2481 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2482 for (i
= 0; values
[i
] != NULL
; i
++)
2484 const struct list
*face_list
;
2485 CHILD_FONT
*child_font
;
2488 if (!strcmpiW(name
,value
))
2490 psub
= get_font_subst(&font_subst_list
, value
, -1);
2492 value
= psub
->to
.name
;
2493 family
= find_family_from_name(value
);
2497 /* Use first extant filename for this Family */
2498 face_list
= get_face_list_from_family(family
);
2499 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2503 file
= strrchrW(face
->file
, '/');
2512 face
= find_face_from_filename(file
, value
);
2515 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2519 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2520 child_font
->face
= face
;
2521 child_font
->font
= NULL
;
2522 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2523 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2524 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2525 child_font
->face
->face_index
);
2526 list_add_tail(&font_link
->links
, &child_font
->entry
);
2528 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2534 /*************************************************************
2537 static BOOL
init_system_links(void)
2541 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2542 WCHAR
*value
, *data
;
2543 WCHAR
*entry
, *next
;
2544 SYSTEM_LINKS
*font_link
, *system_font_link
;
2545 CHILD_FONT
*child_font
;
2546 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2547 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2548 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2553 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2555 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2556 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2557 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2558 val_len
= max_val
+ 1;
2559 data_len
= max_data
;
2561 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2563 psub
= get_font_subst(&font_subst_list
, value
, -1);
2564 /* Don't store fonts that are only substitutes for other fonts */
2567 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2570 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2571 font_link
->font_name
= strdupW(value
);
2572 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2573 list_init(&font_link
->links
);
2574 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2577 CHILD_FONT
*child_font
;
2579 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2581 next
= entry
+ strlenW(entry
) + 1;
2583 face_name
= strchrW(entry
, ',');
2587 while(isspaceW(*face_name
))
2590 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2592 face_name
= psub
->to
.name
;
2594 face
= find_face_from_filename(entry
, face_name
);
2597 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2601 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2602 child_font
->face
= face
;
2603 child_font
->font
= NULL
;
2604 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2605 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2606 TRACE("Adding file %s index %ld\n",
2607 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2608 list_add_tail(&font_link
->links
, &child_font
->entry
);
2610 list_add_tail(&system_links
, &font_link
->entry
);
2612 val_len
= max_val
+ 1;
2613 data_len
= max_data
;
2616 HeapFree(GetProcessHeap(), 0, value
);
2617 HeapFree(GetProcessHeap(), 0, data
);
2622 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2624 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2628 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2630 const FontSubst
*psub2
;
2631 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2633 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2635 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2636 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2638 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2639 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2641 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2643 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2649 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2652 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2653 system_font_link
->font_name
= strdupW(System
);
2654 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2655 list_init(&system_font_link
->links
);
2657 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2660 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2661 child_font
->face
= face
;
2662 child_font
->font
= NULL
;
2663 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2664 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2665 TRACE("Found Tahoma in %s index %ld\n",
2666 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2667 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2669 font_link
= find_font_link(Tahoma
);
2670 if (font_link
!= NULL
)
2672 CHILD_FONT
*font_link_entry
;
2673 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2675 CHILD_FONT
*new_child
;
2676 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2677 new_child
->face
= font_link_entry
->face
;
2678 new_child
->font
= NULL
;
2679 new_child
->face
->refcount
++;
2680 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2681 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2682 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2685 list_add_tail(&system_links
, &system_font_link
->entry
);
2689 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2692 struct dirent
*dent
;
2693 char path
[MAX_PATH
];
2695 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2697 dir
= opendir(dirname
);
2699 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2702 while((dent
= readdir(dir
)) != NULL
) {
2703 struct stat statbuf
;
2705 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2708 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2710 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2712 if(stat(path
, &statbuf
) == -1)
2714 WARN("Can't stat %s\n", debugstr_a(path
));
2717 if(S_ISDIR(statbuf
.st_mode
))
2718 ReadFontDir(path
, external_fonts
);
2721 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2722 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2723 AddFontToList(path
, NULL
, 0, addfont_flags
);
2730 #ifdef SONAME_LIBFONTCONFIG
2732 static BOOL fontconfig_enabled
;
2734 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2740 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2741 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2743 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2747 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2748 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2749 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2750 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2751 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2757 static void init_fontconfig(void)
2759 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2763 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2767 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2768 LOAD_FUNCPTR(FcConfigSubstitute
);
2769 LOAD_FUNCPTR(FcFontList
);
2770 LOAD_FUNCPTR(FcFontSetDestroy
);
2771 LOAD_FUNCPTR(FcInit
);
2772 LOAD_FUNCPTR(FcObjectSetAdd
);
2773 LOAD_FUNCPTR(FcObjectSetCreate
);
2774 LOAD_FUNCPTR(FcObjectSetDestroy
);
2775 LOAD_FUNCPTR(FcPatternCreate
);
2776 LOAD_FUNCPTR(FcPatternDestroy
);
2777 LOAD_FUNCPTR(FcPatternGetBool
);
2778 LOAD_FUNCPTR(FcPatternGetInteger
);
2779 LOAD_FUNCPTR(FcPatternGetString
);
2784 FcPattern
*pattern
= pFcPatternCreate();
2785 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2786 default_aa_flags
= parse_aa_pattern( pattern
);
2787 pFcPatternDestroy( pattern
);
2788 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2789 fontconfig_enabled
= TRUE
;
2793 static void load_fontconfig_fonts(void)
2802 if (!fontconfig_enabled
) return;
2804 pat
= pFcPatternCreate();
2805 os
= pFcObjectSetCreate();
2806 pFcObjectSetAdd(os
, FC_FILE
);
2807 pFcObjectSetAdd(os
, FC_SCALABLE
);
2808 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2809 pFcObjectSetAdd(os
, FC_RGBA
);
2810 fontset
= pFcFontList(NULL
, pat
, os
);
2811 if(!fontset
) return;
2812 for(i
= 0; i
< fontset
->nfont
; i
++) {
2816 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2819 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2821 /* We're just interested in OT/TT fonts for now, so this hack just
2822 picks up the scalable fonts without extensions .pf[ab] to save time
2823 loading every other font */
2825 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2827 TRACE("not scalable\n");
2831 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2832 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2834 len
= strlen( file
);
2835 if(len
< 4) continue;
2836 ext
= &file
[ len
- 3 ];
2837 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2838 AddFontToList(file
, NULL
, 0,
2839 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2841 pFcFontSetDestroy(fontset
);
2842 pFcObjectSetDestroy(os
);
2843 pFcPatternDestroy(pat
);
2846 #elif defined(HAVE_CARBON_CARBON_H)
2848 static void load_mac_font_callback(const void *value
, void *context
)
2850 CFStringRef pathStr
= value
;
2854 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2855 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2856 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2858 TRACE("font file %s\n", path
);
2859 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2861 HeapFree(GetProcessHeap(), 0, path
);
2864 static void load_mac_fonts(void)
2866 CFStringRef removeDupesKey
;
2867 CFBooleanRef removeDupesValue
;
2868 CFDictionaryRef options
;
2869 CTFontCollectionRef col
;
2871 CFMutableSetRef paths
;
2874 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2875 removeDupesValue
= kCFBooleanTrue
;
2876 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2877 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2878 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2879 if (options
) CFRelease(options
);
2882 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2886 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2890 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2894 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2897 WARN("CFSetCreateMutable failed\n");
2902 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2904 CTFontDescriptorRef desc
;
2913 desc
= CFArrayGetValueAtIndex(descs
, i
);
2915 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2916 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2917 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2918 if (!font
) continue;
2920 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2927 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2929 if (status
!= noErr
) continue;
2931 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2934 ext
= CFURLCopyPathExtension(url
);
2937 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2938 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2947 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2949 if (!path
) continue;
2951 CFSetAddValue(paths
, path
);
2957 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2963 static char *get_data_dir_path( LPCWSTR file
)
2965 char *unix_name
= NULL
;
2966 const char *data_dir
= wine_get_data_dir();
2968 if (!data_dir
) data_dir
= wine_get_build_dir();
2972 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2974 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2975 strcpy(unix_name
, data_dir
);
2976 strcat(unix_name
, "/fonts/");
2978 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2983 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2986 char *unix_name
= get_data_dir_path( file
);
2990 EnterCriticalSection( &freetype_cs
);
2991 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2992 LeaveCriticalSection( &freetype_cs
);
2993 HeapFree(GetProcessHeap(), 0, unix_name
);
2998 static char *get_winfonts_dir_path(LPCWSTR file
)
3000 static const WCHAR slashW
[] = {'\\','\0'};
3001 WCHAR windowsdir
[MAX_PATH
];
3003 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3004 strcatW(windowsdir
, fontsW
);
3005 strcatW(windowsdir
, slashW
);
3006 strcatW(windowsdir
, file
);
3007 return wine_get_unix_file_name( windowsdir
);
3010 static void load_system_fonts(void)
3013 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
3014 const WCHAR
* const *value
;
3016 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3019 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3020 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3021 strcatW(windowsdir
, fontsW
);
3022 for(value
= SystemFontValues
; *value
; value
++) {
3023 dlen
= sizeof(data
);
3024 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
3028 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3029 if((unixname
= wine_get_unix_file_name(pathW
))) {
3030 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3031 HeapFree(GetProcessHeap(), 0, unixname
);
3034 load_font_from_data_dir(data
);
3041 /*************************************************************
3043 * This adds registry entries for any externally loaded fonts
3044 * (fonts from fontconfig or FontDirs). It also deletes entries
3045 * of no longer existing fonts.
3048 static void update_reg_entries(void)
3050 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3056 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3058 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3059 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3060 ERR("Can't create Windows font reg key\n");
3064 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3065 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3066 ERR("Can't create Windows font reg key\n");
3070 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
3071 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
3072 ERR("Can't create external font reg key\n");
3076 /* enumerate the fonts and add external ones to the two keys */
3078 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
3079 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
3081 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
3085 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3086 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3087 strcpyW(valueW
, face
->FullName
);
3091 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3092 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3093 strcpyW(valueW
, family
->FamilyName
);
3096 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
3097 path
= wine_get_dos_file_name( buffer
);
3098 HeapFree( GetProcessHeap(), 0, buffer
);
3102 else if ((file
= strrchrW(face
->file
, '/')))
3107 len
= strlenW(file
) + 1;
3108 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3109 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3110 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3112 HeapFree(GetProcessHeap(), 0, path
);
3113 HeapFree(GetProcessHeap(), 0, valueW
);
3117 if(external_key
) RegCloseKey(external_key
);
3118 if(win9x_key
) RegCloseKey(win9x_key
);
3119 if(winnt_key
) RegCloseKey(winnt_key
);
3122 static void delete_external_font_keys(void)
3124 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3125 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
3129 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3130 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3131 ERR("Can't create Windows font reg key\n");
3135 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3136 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3137 ERR("Can't create Windows font reg key\n");
3141 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
3142 ERR("Can't create external font reg key\n");
3146 /* Delete all external fonts added last time */
3148 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3149 &valuelen
, &datalen
, NULL
, NULL
);
3150 valuelen
++; /* returned value doesn't include room for '\0' */
3151 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3152 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3154 dlen
= datalen
* sizeof(WCHAR
);
3157 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
3158 &dlen
) == ERROR_SUCCESS
) {
3160 RegDeleteValueW(winnt_key
, valueW
);
3161 RegDeleteValueW(win9x_key
, valueW
);
3162 /* reset dlen and vlen */
3166 HeapFree(GetProcessHeap(), 0, data
);
3167 HeapFree(GetProcessHeap(), 0, valueW
);
3169 /* Delete the old external fonts key */
3170 RegCloseKey(external_key
);
3171 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
3174 if(win9x_key
) RegCloseKey(win9x_key
);
3175 if(winnt_key
) RegCloseKey(winnt_key
);
3178 /*************************************************************
3179 * WineEngAddFontResourceEx
3182 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3188 if (ft_handle
) /* do it only if we have freetype up and running */
3192 EnterCriticalSection( &freetype_cs
);
3194 if((unixname
= wine_get_unix_file_name(file
)))
3196 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3198 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3199 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
3200 HeapFree(GetProcessHeap(), 0, unixname
);
3202 if (!ret
&& !strchrW(file
, '\\')) {
3203 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3204 if ((unixname
= get_winfonts_dir_path( file
)))
3206 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3207 HeapFree(GetProcessHeap(), 0, unixname
);
3209 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3210 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3212 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3213 HeapFree(GetProcessHeap(), 0, unixname
);
3217 LeaveCriticalSection( &freetype_cs
);
3222 /*************************************************************
3223 * WineEngAddFontMemResourceEx
3226 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3230 if (ft_handle
) /* do it only if we have freetype up and running */
3232 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
3234 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
3235 memcpy(pFontCopy
, pbFont
, cbFont
);
3237 EnterCriticalSection( &freetype_cs
);
3238 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3239 LeaveCriticalSection( &freetype_cs
);
3243 TRACE("AddFontToList failed\n");
3244 HeapFree(GetProcessHeap(), 0, pFontCopy
);
3247 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3248 * For now return something unique but quite random
3250 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
3251 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
3258 /*************************************************************
3259 * WineEngRemoveFontResourceEx
3262 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3268 if (ft_handle
) /* do it only if we have freetype up and running */
3272 EnterCriticalSection( &freetype_cs
);
3274 if ((unixname
= wine_get_unix_file_name(file
)))
3276 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3278 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3279 ret
= remove_font_resource( unixname
, addfont_flags
);
3280 HeapFree(GetProcessHeap(), 0, unixname
);
3282 if (!ret
&& !strchrW(file
, '\\'))
3284 if ((unixname
= get_winfonts_dir_path( file
)))
3286 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3287 HeapFree(GetProcessHeap(), 0, unixname
);
3289 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3291 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3292 HeapFree(GetProcessHeap(), 0, unixname
);
3296 LeaveCriticalSection( &freetype_cs
);
3301 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3307 if (!font_file
) return NULL
;
3309 file_len
= strlenW( font_file
);
3311 if (font_path
&& font_path
[0])
3313 int path_len
= strlenW( font_path
);
3314 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3315 if (!fullname
) return NULL
;
3316 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3317 fullname
[path_len
] = '\\';
3318 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3322 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3323 if (!len
) return NULL
;
3324 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3325 if (!fullname
) return NULL
;
3326 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3329 unix_name
= wine_get_unix_file_name( fullname
);
3330 HeapFree( GetProcessHeap(), 0, fullname
);
3334 #include <pshpack1.h>
3337 WORD num_of_resources
;
3341 CHAR dfCopyright
[60];
3347 WORD dfInternalLeading
;
3348 WORD dfExternalLeading
;
3356 BYTE dfPitchAndFamily
;
3367 CHAR szFaceName
[LF_FACESIZE
];
3370 #include <poppack.h>
3372 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3373 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3375 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3377 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3379 WCHAR
*name
, *english_name
;
3381 NEWTEXTMETRICEXW ntm
;
3384 if (!ft_face
) return FALSE
;
3385 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3386 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3387 pFT_Done_Face( ft_face
);
3389 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3390 release_face( face
);
3391 HeapFree( GetProcessHeap(), 0, name
);
3392 HeapFree( GetProcessHeap(), 0, english_name
);
3394 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3396 memset( fd
, 0, sizeof(*fd
) );
3398 fd
->num_of_resources
= 1;
3400 fd
->dfVersion
= 0x200;
3401 fd
->dfSize
= sizeof(*fd
);
3402 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3403 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3404 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3406 fd
->dfHorizRes
= 72;
3407 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3408 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3409 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3410 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3411 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3412 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3413 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3414 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3416 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3417 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3418 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3419 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3420 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3421 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3422 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3423 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3424 fd
->dfWidthBytes
= 0;
3426 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3428 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3433 #define NE_FFLAGS_LIBMODULE 0x8000
3434 #define NE_OSFLAGS_WINDOWS 0x02
3436 static const char dos_string
[0x40] = "This is a TrueType resource file";
3437 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3439 #include <pshpack2.h>
3460 struct ne_typeinfo fontdir_type
;
3461 struct ne_nameinfo fontdir_name
;
3462 struct ne_typeinfo scalable_type
;
3463 struct ne_nameinfo scalable_name
;
3465 BYTE fontdir_res_name
[8];
3468 #include <poppack.h>
3470 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3474 DWORD size
, written
;
3476 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3477 char *font_fileA
, *last_part
, *ext
;
3478 IMAGE_DOS_HEADER dos
;
3479 IMAGE_OS2_HEADER ne
=
3481 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3483 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3484 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3486 struct rsrc_tab rsrc_tab
=
3490 { 0, 0, 0x0c50, 0x2c, 0 },
3492 { 0, 0, 0x0c50, 0x8001, 0 },
3494 { 7,'F','O','N','T','D','I','R'}
3497 memset( &dos
, 0, sizeof(dos
) );
3498 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3499 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3501 /* import name is last part\0, resident name is last part without extension
3502 non-resident name is "FONTRES:" + lfFaceName */
3504 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3505 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3506 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3508 last_part
= strrchr( font_fileA
, '\\' );
3509 if (last_part
) last_part
++;
3510 else last_part
= font_fileA
;
3511 import_name_len
= strlen( last_part
) + 1;
3513 ext
= strchr( last_part
, '.' );
3514 if (ext
) res_name_len
= ext
- last_part
;
3515 else res_name_len
= import_name_len
- 1;
3517 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3519 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3520 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3521 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3522 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3524 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3526 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3527 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3528 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3529 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3531 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3532 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3536 HeapFree( GetProcessHeap(), 0, font_fileA
);
3540 memcpy( ptr
, &dos
, sizeof(dos
) );
3541 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3542 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3544 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3545 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3547 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3548 *ptr
++ = res_name_len
;
3549 memcpy( ptr
, last_part
, res_name_len
);
3551 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3552 *ptr
++ = import_name_len
;
3553 memcpy( ptr
, last_part
, import_name_len
);
3555 ptr
= start
+ ne
.ne_nrestab
;
3556 *ptr
++ = non_res_name_len
;
3557 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3558 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3560 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3561 memcpy( ptr
, font_fileA
, font_file_len
);
3563 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3564 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3566 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3567 if (file
!= INVALID_HANDLE_VALUE
)
3569 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3571 CloseHandle( file
);
3574 HeapFree( GetProcessHeap(), 0, start
);
3575 HeapFree( GetProcessHeap(), 0, font_fileA
);
3580 /*************************************************************
3581 * WineEngCreateScalableFontResource
3584 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3585 LPCWSTR font_file
, LPCWSTR font_path
)
3587 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3588 struct fontdir fontdir
;
3591 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3592 SetLastError( ERROR_INVALID_PARAMETER
);
3595 if (hidden
) fontdir
.dfType
|= 0x80;
3596 ret
= create_fot( resource
, font_file
, &fontdir
);
3599 HeapFree( GetProcessHeap(), 0, unix_name
);
3603 static const struct nls_update_font_list
3605 UINT ansi_cp
, oem_cp
;
3606 const char *oem
, *fixed
, *system
;
3607 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3608 /* these are for font substitutes */
3609 const char *shelldlg
, *tmsrmn
;
3610 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3614 const char *from
, *to
;
3615 } arial_0
, courier_new_0
, times_new_roman_0
;
3616 } nls_update_font_list
[] =
3618 /* Latin 1 (United States) */
3619 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3620 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3621 "Tahoma","Times New Roman",
3622 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3625 /* Latin 1 (Multilingual) */
3626 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3627 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3628 "Tahoma","Times New Roman", /* FIXME unverified */
3629 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3632 /* Eastern Europe */
3633 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3634 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3635 "Tahoma","Times New Roman", /* FIXME unverified */
3636 "Fixedsys,238", "System,238",
3637 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3638 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3639 { "Arial CE,0", "Arial,238" },
3640 { "Courier New CE,0", "Courier New,238" },
3641 { "Times New Roman CE,0", "Times New Roman,238" }
3644 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3645 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3646 "Tahoma","Times New Roman", /* FIXME unverified */
3647 "Fixedsys,204", "System,204",
3648 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3649 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3650 { "Arial Cyr,0", "Arial,204" },
3651 { "Courier New Cyr,0", "Courier New,204" },
3652 { "Times New Roman Cyr,0", "Times New Roman,204" }
3655 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3656 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3657 "Tahoma","Times New Roman", /* FIXME unverified */
3658 "Fixedsys,161", "System,161",
3659 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3660 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3661 { "Arial Greek,0", "Arial,161" },
3662 { "Courier New Greek,0", "Courier New,161" },
3663 { "Times New Roman Greek,0", "Times New Roman,161" }
3666 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3667 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3668 "Tahoma","Times New Roman", /* FIXME unverified */
3669 "Fixedsys,162", "System,162",
3670 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3671 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3672 { "Arial Tur,0", "Arial,162" },
3673 { "Courier New Tur,0", "Courier New,162" },
3674 { "Times New Roman Tur,0", "Times New Roman,162" }
3677 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3678 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3679 "Tahoma","Times New Roman", /* FIXME unverified */
3680 "Fixedsys,177", "System,177",
3681 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3682 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3686 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3687 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3688 "Microsoft Sans Serif","Times New Roman",
3689 "Fixedsys,178", "System,178",
3690 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3691 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3695 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3696 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3697 "Tahoma","Times New Roman", /* FIXME unverified */
3698 "Fixedsys,186", "System,186",
3699 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3700 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3701 { "Arial Baltic,0", "Arial,186" },
3702 { "Courier New Baltic,0", "Courier New,186" },
3703 { "Times New Roman Baltic,0", "Times New Roman,186" }
3706 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3707 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3708 "Tahoma","Times New Roman", /* FIXME unverified */
3709 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3713 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3714 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3715 "Tahoma","Times New Roman", /* FIXME unverified */
3716 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3720 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3721 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3722 "MS UI Gothic","MS Serif",
3723 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3726 /* Chinese Simplified */
3727 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3728 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3729 "SimSun", "NSimSun",
3730 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3734 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3735 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3737 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3740 /* Chinese Traditional */
3741 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3742 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3743 "PMingLiU", "MingLiU",
3744 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3749 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3751 return ( ansi_cp
== 932 /* CP932 for Japanese */
3752 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3753 || ansi_cp
== 949 /* CP949 for Korean */
3754 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3757 static inline HKEY
create_fonts_NT_registry_key(void)
3761 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3762 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3766 static inline HKEY
create_fonts_9x_registry_key(void)
3770 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3771 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3775 static inline HKEY
create_config_fonts_registry_key(void)
3779 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3780 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3784 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3786 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3788 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3789 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3790 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3791 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3794 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3797 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3799 RegDeleteValueA(hkey
, name
);
3802 static void update_font_association_info(UINT current_ansi_codepage
)
3804 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3805 static const char *assoc_charset_subkey
= "Associated Charset";
3807 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3810 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3813 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3815 switch (current_ansi_codepage
)
3818 set_value_key(hsubkey
, "ANSI(00)", "NO");
3819 set_value_key(hsubkey
, "OEM(FF)", "NO");
3820 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3825 set_value_key(hsubkey
, "ANSI(00)", "YES");
3826 set_value_key(hsubkey
, "OEM(FF)", "YES");
3827 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3830 RegCloseKey(hsubkey
);
3833 /* TODO: Associated DefaultFonts */
3839 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3842 static void set_multi_value_key(HKEY hkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD len
)
3845 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (const BYTE
*)value
, len
);
3847 RegDeleteValueW(hkey
, name
);
3850 static void update_font_system_link_info(UINT current_ansi_codepage
)
3852 static const WCHAR system_link_simplified_chinese
[] =
3853 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3854 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3855 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3856 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3858 static const WCHAR system_link_traditional_chinese
[] =
3859 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3860 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3861 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3862 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3864 static const WCHAR system_link_japanese
[] =
3865 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3866 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3867 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3868 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3870 static const WCHAR system_link_korean
[] =
3871 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3872 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3873 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3874 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3876 static const WCHAR system_link_non_cjk
[] =
3877 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3878 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3879 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3880 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3884 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
3889 switch (current_ansi_codepage
)
3892 link
= system_link_japanese
;
3893 len
= sizeof(system_link_japanese
);
3896 link
= system_link_simplified_chinese
;
3897 len
= sizeof(system_link_simplified_chinese
);
3900 link
= system_link_korean
;
3901 len
= sizeof(system_link_korean
);
3904 link
= system_link_traditional_chinese
;
3905 len
= sizeof(system_link_traditional_chinese
);
3908 link
= system_link_non_cjk
;
3909 len
= sizeof(system_link_non_cjk
);
3911 set_multi_value_key(hkey
, Lucida_Sans_Unicode
, link
, len
);
3912 set_multi_value_key(hkey
, Microsoft_Sans_Serif
, link
, len
);
3913 set_multi_value_key(hkey
, Tahoma
, link
, len
);
3918 static void update_font_info(void)
3920 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3921 char buf
[40], cpbuf
[40];
3924 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3925 DWORD screen_dpi
= 96, font_dpi
= 0;
3928 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3929 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3930 &hkey
) == ERROR_SUCCESS
)
3932 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3936 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3939 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3941 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3942 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3943 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3944 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3945 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3947 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3948 if (is_dbcs_ansi_cp(ansi_cp
))
3949 use_default_fallback
= TRUE
;
3953 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3955 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3960 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3961 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3963 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3964 ansi_cp
, oem_cp
, screen_dpi
);
3966 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3967 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3970 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3974 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3975 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3977 hkey
= create_config_fonts_registry_key();
3978 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3979 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3980 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3983 hkey
= create_fonts_NT_registry_key();
3984 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3987 hkey
= create_fonts_9x_registry_key();
3988 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3991 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3993 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3994 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3995 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3996 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3998 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3999 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
4000 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
4001 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
4002 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
4003 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
4004 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
4005 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
4007 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
4008 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
4009 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
4017 /* Delete the FontSubstitutes from other locales */
4018 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
4020 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
4021 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
4022 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
4028 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
4030 /* update locale dependent font association info and font system link info in registry.
4031 update only when codepages changed, not logpixels. */
4032 if (strcmp(buf
, cpbuf
) != 0)
4034 update_font_association_info(ansi_cp
);
4035 update_font_system_link_info(ansi_cp
);
4039 static BOOL
init_freetype(void)
4041 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
4044 "Wine cannot find the FreeType font library. To enable Wine to\n"
4045 "use TrueType fonts please install a version of FreeType greater than\n"
4046 "or equal to 2.0.5.\n"
4047 "http://www.freetype.org\n");
4051 #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;}
4053 LOAD_FUNCPTR(FT_Done_Face
)
4054 LOAD_FUNCPTR(FT_Get_Char_Index
)
4055 LOAD_FUNCPTR(FT_Get_First_Char
)
4056 LOAD_FUNCPTR(FT_Get_Next_Char
)
4057 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
4058 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
4059 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
4060 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
4061 LOAD_FUNCPTR(FT_Init_FreeType
)
4062 LOAD_FUNCPTR(FT_Library_Version
)
4063 LOAD_FUNCPTR(FT_Load_Glyph
)
4064 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
4065 LOAD_FUNCPTR(FT_Matrix_Multiply
)
4066 #ifndef FT_MULFIX_INLINED
4067 LOAD_FUNCPTR(FT_MulFix
)
4069 LOAD_FUNCPTR(FT_New_Face
)
4070 LOAD_FUNCPTR(FT_New_Memory_Face
)
4071 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
4072 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
4073 LOAD_FUNCPTR(FT_Outline_Transform
)
4074 LOAD_FUNCPTR(FT_Outline_Translate
)
4075 LOAD_FUNCPTR(FT_Render_Glyph
)
4076 LOAD_FUNCPTR(FT_Select_Charmap
)
4077 LOAD_FUNCPTR(FT_Set_Charmap
)
4078 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
4079 LOAD_FUNCPTR(FT_Vector_Transform
)
4080 LOAD_FUNCPTR(FT_Vector_Unit
)
4082 /* Don't warn if these ones are missing */
4083 pFT_Outline_Embolden
= wine_dlsym(ft_handle
, "FT_Outline_Embolden", NULL
, 0);
4084 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
4085 #ifdef FT_LCD_FILTER_H
4086 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
4089 if(pFT_Init_FreeType(&library
) != 0) {
4090 ERR("Can't init FreeType library\n");
4091 wine_dlclose(ft_handle
, NULL
, 0);
4095 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
4097 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
4098 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
4099 ((FT_Version
.minor
<< 8) & 0x00ff00) |
4100 ((FT_Version
.patch
) & 0x0000ff);
4102 font_driver
= &freetype_funcs
;
4107 "Wine cannot find certain functions that it needs inside the FreeType\n"
4108 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4109 "FreeType to at least version 2.1.4.\n"
4110 "http://www.freetype.org\n");
4111 wine_dlclose(ft_handle
, NULL
, 0);
4116 static void init_font_list(void)
4118 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
4119 static const WCHAR pathW
[] = {'P','a','t','h',0};
4121 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
4122 WCHAR windowsdir
[MAX_PATH
];
4124 const char *data_dir
;
4126 delete_external_font_keys();
4128 /* load the system bitmap fonts */
4129 load_system_fonts();
4131 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4132 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
4133 strcatW(windowsdir
, fontsW
);
4134 if((unixname
= wine_get_unix_file_name(windowsdir
)))
4136 ReadFontDir(unixname
, FALSE
);
4137 HeapFree(GetProcessHeap(), 0, unixname
);
4140 /* load the system truetype fonts */
4141 data_dir
= wine_get_data_dir();
4142 if (!data_dir
) data_dir
= wine_get_build_dir();
4143 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
4145 strcpy(unixname
, data_dir
);
4146 strcat(unixname
, "/fonts/");
4147 ReadFontDir(unixname
, TRUE
);
4148 HeapFree(GetProcessHeap(), 0, unixname
);
4151 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4152 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4153 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4155 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
4156 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
4157 &hkey
) == ERROR_SUCCESS
)
4159 LPWSTR data
, valueW
;
4160 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4161 &valuelen
, &datalen
, NULL
, NULL
);
4163 valuelen
++; /* returned value doesn't include room for '\0' */
4164 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
4165 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
4168 dlen
= datalen
* sizeof(WCHAR
);
4170 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
4171 &dlen
) == ERROR_SUCCESS
)
4173 if(data
[0] && (data
[1] == ':'))
4175 if((unixname
= wine_get_unix_file_name(data
)))
4177 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4178 HeapFree(GetProcessHeap(), 0, unixname
);
4181 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
4183 WCHAR pathW
[MAX_PATH
];
4184 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
4187 sprintfW(pathW
, fmtW
, windowsdir
, data
);
4188 if((unixname
= wine_get_unix_file_name(pathW
)))
4190 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4191 HeapFree(GetProcessHeap(), 0, unixname
);
4194 load_font_from_data_dir(data
);
4196 /* reset dlen and vlen */
4201 HeapFree(GetProcessHeap(), 0, data
);
4202 HeapFree(GetProcessHeap(), 0, valueW
);
4206 #ifdef SONAME_LIBFONTCONFIG
4207 load_fontconfig_fonts();
4208 #elif defined(HAVE_CARBON_CARBON_H)
4212 /* then look in any directories that we've specified in the config file */
4213 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4214 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
4220 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
4222 len
+= sizeof(WCHAR
);
4223 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
4224 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
4226 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
4227 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
4228 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
4229 TRACE( "got font path %s\n", debugstr_a(valueA
) );
4234 LPSTR next
= strchr( ptr
, ':' );
4235 if (next
) *next
++ = 0;
4236 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
4237 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
4239 strcpy( unixname
, home
);
4240 strcat( unixname
, ptr
+ 1 );
4241 ReadFontDir( unixname
, TRUE
);
4242 HeapFree( GetProcessHeap(), 0, unixname
);
4245 ReadFontDir( ptr
, TRUE
);
4248 HeapFree( GetProcessHeap(), 0, valueA
);
4250 HeapFree( GetProcessHeap(), 0, valueW
);
4256 static BOOL
move_to_front(const WCHAR
*name
)
4258 Family
*family
, *cursor2
;
4259 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
4261 if(!strcmpiW(family
->FamilyName
, name
))
4263 list_remove(&family
->entry
);
4264 list_add_head(&font_list
, &family
->entry
);
4271 static BOOL
set_default(const WCHAR
**name_list
)
4275 if (move_to_front(*name_list
)) return TRUE
;
4282 static void reorder_font_list(void)
4284 set_default( default_serif_list
);
4285 set_default( default_fixed_list
);
4286 set_default( default_sans_list
);
4289 /*************************************************************
4292 * Initialize FreeType library and create a list of available faces
4294 BOOL
WineEngInit(void)
4300 /* update locale dependent font info in registry */
4303 if(!init_freetype()) return FALSE
;
4305 #ifdef SONAME_LIBFONTCONFIG
4309 if (!RegOpenKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, KEY_READ
, &hkey
))
4311 static const WCHAR antialias_fake_bold_or_italic
[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4312 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4313 static const WCHAR true_options
[] = { 'y','Y','t','T','1',0 };
4317 size
= sizeof(buffer
);
4318 if (!RegQueryValueExW(hkey
, antialias_fake_bold_or_italic
, NULL
, &type
, (BYTE
*)buffer
, &size
) &&
4319 type
== REG_SZ
&& size
>= 1)
4321 antialias_fakes
= (strchrW(true_options
, buffer
[0]) != NULL
);
4326 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
4328 ERR("Failed to create font mutex\n");
4331 WaitForSingleObject(font_mutex
, INFINITE
);
4333 create_font_cache_key(&hkey_font_cache
, &disposition
);
4335 if(disposition
== REG_CREATED_NEW_KEY
)
4338 load_font_list_from_cache(hkey_font_cache
);
4340 reorder_font_list();
4347 if(disposition
== REG_CREATED_NEW_KEY
)
4348 update_reg_entries();
4350 init_system_links();
4352 ReleaseMutex(font_mutex
);
4356 /* Some fonts have large usWinDescent values, as a result of storing signed short
4357 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4358 some font generation tools. */
4359 static inline USHORT
get_fixed_windescent(USHORT windescent
)
4361 return abs((SHORT
)windescent
);
4364 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
4367 TT_HoriHeader
*pHori
;
4370 const LONG MAX_PPEM
= (1 << 16) - 1;
4372 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4373 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4375 if(height
== 0) height
= 16;
4377 /* Calc. height of EM square:
4379 * For +ve lfHeight we have
4380 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4381 * Re-arranging gives:
4382 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4384 * For -ve lfHeight we have
4386 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4387 * with il = winAscent + winDescent - units_per_em]
4392 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
4393 if(pOS2
->usWinAscent
+ windescent
== 0)
4394 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4395 pHori
->Ascender
- pHori
->Descender
);
4397 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4398 pOS2
->usWinAscent
+ windescent
);
4399 if(ppem
> MAX_PPEM
) {
4400 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4404 else if(height
>= -MAX_PPEM
)
4407 WARN("Ignoring too large height %d\n", height
);
4414 static struct font_mapping
*map_font_file( const char *name
)
4416 struct font_mapping
*mapping
;
4420 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4421 if (fstat( fd
, &st
) == -1) goto error
;
4423 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4425 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4427 mapping
->refcount
++;
4432 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4435 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4438 if (mapping
->data
== MAP_FAILED
)
4440 HeapFree( GetProcessHeap(), 0, mapping
);
4443 mapping
->refcount
= 1;
4444 mapping
->dev
= st
.st_dev
;
4445 mapping
->ino
= st
.st_ino
;
4446 mapping
->size
= st
.st_size
;
4447 list_add_tail( &mappings_list
, &mapping
->entry
);
4455 static void unmap_font_file( struct font_mapping
*mapping
)
4457 if (!--mapping
->refcount
)
4459 list_remove( &mapping
->entry
);
4460 munmap( mapping
->data
, mapping
->size
);
4461 HeapFree( GetProcessHeap(), 0, mapping
);
4465 static LONG
load_VDMX(GdiFont
*, LONG
);
4467 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4474 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4478 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4479 font
->mapping
= map_font_file( filename
);
4480 HeapFree( GetProcessHeap(), 0, filename
);
4483 WARN("failed to map %s\n", debugstr_w(face
->file
));
4486 data_ptr
= font
->mapping
->data
;
4487 data_size
= font
->mapping
->size
;
4491 data_ptr
= face
->font_data_ptr
;
4492 data_size
= face
->font_data_size
;
4495 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4497 ERR("FT_New_Face rets %d\n", err
);
4501 /* set it here, as load_VDMX needs it */
4502 font
->ft_face
= ft_face
;
4504 if(FT_IS_SCALABLE(ft_face
)) {
4505 /* load the VDMX table if we have one */
4506 font
->ppem
= load_VDMX(font
, height
);
4508 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4509 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4511 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4512 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4514 font
->ppem
= height
;
4515 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4516 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4522 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4524 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4525 a single face with the requested charset. The idea is to check if
4526 the selected font supports the current ANSI codepage, if it does
4527 return the corresponding charset, else return the first charset */
4530 int acp
= GetACP(), i
;
4534 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4536 const SYSTEM_LINKS
*font_link
;
4538 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4539 return csi
.ciCharset
;
4541 font_link
= find_font_link(family_name
);
4542 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4543 return csi
.ciCharset
;
4546 for(i
= 0; i
< 32; i
++) {
4548 if(face
->fs
.fsCsb
[0] & fs0
) {
4549 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4551 return csi
.ciCharset
;
4554 FIXME("TCI failing on %x\n", fs0
);
4558 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4559 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4561 return DEFAULT_CHARSET
;
4564 static GdiFont
*alloc_font(void)
4566 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4569 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4570 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4572 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4573 ret
->total_kern_pairs
= (DWORD
)-1;
4574 ret
->kern_pairs
= NULL
;
4575 ret
->instance_id
= alloc_font_handle(ret
);
4576 list_init(&ret
->child_fonts
);
4580 static void free_font(GdiFont
*font
)
4582 CHILD_FONT
*child
, *child_next
;
4585 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4587 list_remove(&child
->entry
);
4589 free_font(child
->font
);
4590 release_face( child
->face
);
4591 HeapFree(GetProcessHeap(), 0, child
);
4594 HeapFree(GetProcessHeap(), 0, font
->fileinfo
);
4595 free_font_handle(font
->instance_id
);
4596 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4597 if (font
->mapping
) unmap_font_file( font
->mapping
);
4598 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4599 HeapFree(GetProcessHeap(), 0, font
->potm
);
4600 HeapFree(GetProcessHeap(), 0, font
->name
);
4601 for (i
= 0; i
< font
->gmsize
; i
++)
4602 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4603 HeapFree(GetProcessHeap(), 0, font
->gm
);
4604 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4605 HeapFree(GetProcessHeap(), 0, font
);
4609 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4611 FT_Face ft_face
= font
->ft_face
;
4615 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4622 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4624 /* make sure value of len is the value freetype says it needs */
4627 FT_ULong needed
= 0;
4628 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4629 if( !err
&& needed
< len
) len
= needed
;
4631 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4634 TRACE("Can't find table %c%c%c%c\n",
4635 /* bytes were reversed */
4636 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4637 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4643 /*************************************************************
4646 * load the vdmx entry for the specified height
4649 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4650 ( ( (FT_ULong)_x4 << 24 ) | \
4651 ( (FT_ULong)_x3 << 16 ) | \
4652 ( (FT_ULong)_x2 << 8 ) | \
4655 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4682 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4686 BYTE devXRatio
, devYRatio
;
4687 USHORT numRecs
, numRatios
;
4688 DWORD result
, offset
= -1;
4692 result
= get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
4694 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4697 /* FIXME: need the real device aspect ratio */
4701 numRecs
= GET_BE_WORD(hdr
.numRecs
);
4702 numRatios
= GET_BE_WORD(hdr
.numRatios
);
4704 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
4705 for(i
= 0; i
< numRatios
; i
++) {
4708 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
4709 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4712 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4714 if (!ratio
.bCharSet
) continue;
4716 if((ratio
.xRatio
== 0 &&
4717 ratio
.yStartRatio
== 0 &&
4718 ratio
.yEndRatio
== 0) ||
4719 (devXRatio
== ratio
.xRatio
&&
4720 devYRatio
>= ratio
.yStartRatio
&&
4721 devYRatio
<= ratio
.yEndRatio
))
4725 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
4726 get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
4727 offset
= GET_BE_WORD(group_offset
);
4732 if(offset
== -1) return 0;
4734 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
4736 BYTE startsz
, endsz
;
4739 recs
= GET_BE_WORD(group
.recs
);
4740 startsz
= group
.startsz
;
4741 endsz
= group
.endsz
;
4743 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4745 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
4746 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
4747 if(result
== GDI_ERROR
) {
4748 FIXME("Failed to retrieve vTable\n");
4753 for(i
= 0; i
< recs
; i
++) {
4754 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4755 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4756 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4758 if(yMax
+ -yMin
== height
) {
4761 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4764 if(yMax
+ -yMin
> height
) {
4767 goto end
; /* failed */
4769 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4770 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4771 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4772 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4778 TRACE("ppem not found for height %d\n", height
);
4782 if(ppem
< startsz
|| ppem
> endsz
)
4788 for(i
= 0; i
< recs
; i
++) {
4790 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4792 if(yPelHeight
> ppem
)
4798 if(yPelHeight
== ppem
) {
4799 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4800 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4801 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4807 HeapFree(GetProcessHeap(), 0, vTable
);
4813 static void dump_gdi_font_list(void)
4817 TRACE("---------- Font Cache ----------\n");
4818 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4819 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4820 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4823 static void grab_font( GdiFont
*font
)
4825 if (!font
->refcount
++)
4827 list_remove( &font
->unused_entry
);
4828 unused_font_count
--;
4832 static void release_font( GdiFont
*font
)
4835 if (!--font
->refcount
)
4837 TRACE( "font %p\n", font
);
4839 /* add it to the unused list */
4840 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4841 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4843 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4844 TRACE( "freeing %p\n", font
);
4845 list_remove( &font
->entry
);
4846 list_remove( &font
->unused_entry
);
4849 else unused_font_count
++;
4851 if (TRACE_ON(font
)) dump_gdi_font_list();
4855 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4857 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4858 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4859 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4860 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4861 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4864 static void calc_hash(FONT_DESC
*pfd
)
4866 DWORD hash
= 0, *ptr
, two_chars
;
4870 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4872 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4874 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4876 pwc
= (WCHAR
*)&two_chars
;
4878 *pwc
= toupperW(*pwc
);
4880 *pwc
= toupperW(*pwc
);
4884 hash
^= !pfd
->can_use_bitmap
;
4888 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4895 fd
.can_use_bitmap
= can_use_bitmap
;
4898 /* try the in-use list */
4899 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4901 if(fontcmp(ret
, &fd
)) continue;
4902 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4903 list_remove( &ret
->entry
);
4904 list_add_head( &gdi_font_list
, &ret
->entry
);
4911 static void add_to_cache(GdiFont
*font
)
4913 static DWORD cache_num
= 1;
4915 font
->cache_num
= cache_num
++;
4916 list_add_head(&gdi_font_list
, &font
->entry
);
4917 TRACE( "font %p\n", font
);
4920 /*************************************************************
4921 * create_child_font_list
4923 static BOOL
create_child_font_list(GdiFont
*font
)
4926 SYSTEM_LINKS
*font_link
;
4927 CHILD_FONT
*font_link_entry
, *new_child
;
4931 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4932 font_name
= psub
? psub
->to
.name
: font
->name
;
4933 font_link
= find_font_link(font_name
);
4934 if (font_link
!= NULL
)
4936 TRACE("found entry in system list\n");
4937 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4939 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4940 new_child
->face
= font_link_entry
->face
;
4941 new_child
->font
= NULL
;
4942 new_child
->face
->refcount
++;
4943 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4944 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4949 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4950 * Sans Serif. This is how asian windows get default fallbacks for fonts
4952 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4953 font
->charset
!= OEM_CHARSET
&&
4954 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4956 font_link
= find_font_link(szDefaultFallbackLink
);
4957 if (font_link
!= NULL
)
4959 TRACE("found entry in default fallback list\n");
4960 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4962 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4963 new_child
->face
= font_link_entry
->face
;
4964 new_child
->font
= NULL
;
4965 new_child
->face
->refcount
++;
4966 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4967 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4976 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4978 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4980 if (pFT_Set_Charmap
)
4983 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4985 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4987 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4989 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4991 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4992 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4994 switch (ft_face
->charmaps
[i
]->platform_id
)
4997 cmap_def
= ft_face
->charmaps
[i
];
4999 case 0: /* Apple Unicode */
5000 cmap0
= ft_face
->charmaps
[i
];
5002 case 1: /* Macintosh */
5003 cmap1
= ft_face
->charmaps
[i
];
5006 cmap2
= ft_face
->charmaps
[i
];
5008 case 3: /* Microsoft */
5009 cmap3
= ft_face
->charmaps
[i
];
5014 if (cmap3
) /* prefer Microsoft cmap table */
5015 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
5017 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
5019 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
5021 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
5023 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
5025 return ft_err
== FT_Err_Ok
;
5028 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
5032 /*************************************************************
5035 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
5036 LPCWSTR output
, const DEVMODEW
*devmode
)
5038 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
5040 if (!physdev
) return FALSE
;
5041 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
5046 /*************************************************************
5049 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
5051 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5052 release_font( physdev
->font
);
5053 HeapFree( GetProcessHeap(), 0, physdev
);
5057 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
5059 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
5060 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
5061 const FT_Encoding
*encs
= regular_order
;
5063 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
5067 if (select_charmap( face
, *encs
)) break;
5073 #define GASP_GRIDFIT 0x01
5074 #define GASP_DOGRAY 0x02
5075 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
5077 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
5080 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
5081 WORD
*alloced
= NULL
, *ptr
= buf
;
5082 WORD num_recs
, version
;
5086 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
5087 if (size
== GDI_ERROR
) return FALSE
;
5088 if (size
< 4 * sizeof(WORD
)) return FALSE
;
5089 if (size
> sizeof(buf
))
5091 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
5092 if (!ptr
) return FALSE
;
5095 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
5097 version
= GET_BE_WORD( *ptr
++ );
5098 num_recs
= GET_BE_WORD( *ptr
++ );
5100 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
5102 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
5108 *flags
= GET_BE_WORD( *(ptr
+ 1) );
5109 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
5112 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
5116 HeapFree( GetProcessHeap(), 0, alloced
);
5120 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5122 const GSUB_ScriptList
*script
;
5123 const GSUB_Script
*deflt
= NULL
;
5125 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5127 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5128 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5130 const GSUB_Script
*scr
;
5133 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5134 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5136 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5138 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5144 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5148 const GSUB_LangSys
*Lang
;
5150 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5152 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5154 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5155 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5157 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5160 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5163 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5169 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5172 const GSUB_FeatureList
*feature
;
5173 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5175 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5176 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5178 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5179 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5181 const GSUB_Feature
*feat
;
5182 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5189 static const char* get_opentype_script(const GdiFont
*font
)
5192 * I am not sure if this is the correct way to generate our script tag
5195 switch (font
->charset
)
5197 case ANSI_CHARSET
: return "latn";
5198 case BALTIC_CHARSET
: return "latn"; /* ?? */
5199 case CHINESEBIG5_CHARSET
: return "hani";
5200 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5201 case GB2312_CHARSET
: return "hani";
5202 case GREEK_CHARSET
: return "grek";
5203 case HANGUL_CHARSET
: return "hang";
5204 case RUSSIAN_CHARSET
: return "cyrl";
5205 case SHIFTJIS_CHARSET
: return "kana";
5206 case TURKISH_CHARSET
: return "latn"; /* ?? */
5207 case VIETNAMESE_CHARSET
: return "latn";
5208 case JOHAB_CHARSET
: return "latn"; /* ?? */
5209 case ARABIC_CHARSET
: return "arab";
5210 case HEBREW_CHARSET
: return "hebr";
5211 case THAI_CHARSET
: return "thai";
5212 default: return "latn";
5216 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
5218 const GSUB_Header
*header
;
5219 const GSUB_Script
*script
;
5220 const GSUB_LangSys
*language
;
5221 const GSUB_Feature
*feature
;
5223 if (!font
->GSUB_Table
)
5226 header
= font
->GSUB_Table
;
5228 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5231 TRACE("Script not found\n");
5234 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5237 TRACE("Language not found\n");
5240 feature
= GSUB_get_feature(header
, language
, "vrt2");
5242 feature
= GSUB_get_feature(header
, language
, "vert");
5245 TRACE("vrt2/vert feature not found\n");
5251 static void fill_fileinfo_from_face( GdiFont
*font
, Face
*face
)
5253 WIN32_FILE_ATTRIBUTE_DATA info
;
5258 font
->fileinfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*font
->fileinfo
));
5262 len
= strlenW(face
->file
);
5263 font
->fileinfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font
->fileinfo
) + len
* sizeof(WCHAR
));
5264 if (GetFileAttributesExW(face
->file
, GetFileExInfoStandard
, &info
))
5266 font
->fileinfo
->writetime
= info
.ftLastWriteTime
;
5267 font
->fileinfo
->size
.QuadPart
= (LONGLONG
)info
.nFileSizeHigh
<< 32 | info
.nFileSizeLow
;
5268 strcpyW(font
->fileinfo
->path
, face
->file
);
5271 memset(font
->fileinfo
, 0, sizeof(*font
->fileinfo
) + len
* sizeof(WCHAR
));
5274 /*************************************************************
5275 * freetype_SelectFont
5277 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5279 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5281 Face
*face
, *best
, *best_bitmap
;
5282 Family
*family
, *last_resort_family
;
5283 const struct list
*face_list
;
5284 INT height
, width
= 0;
5285 unsigned int score
= 0, new_score
;
5286 signed int diff
= 0, newdiff
;
5287 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5291 FontSubst
*psub
= NULL
;
5292 DC
*dc
= get_dc_ptr( dev
->hdc
);
5293 const SYSTEM_LINKS
*font_link
;
5295 if (!hfont
) /* notification that the font has been changed by another driver */
5297 release_font( physdev
->font
);
5298 physdev
->font
= NULL
;
5299 release_dc_ptr( dc
);
5303 GetObjectW( hfont
, sizeof(lf
), &lf
);
5304 lf
.lfWidth
= abs(lf
.lfWidth
);
5306 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5308 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5309 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5310 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5313 if(dc
->GraphicsMode
== GM_ADVANCED
)
5315 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5316 /* Try to avoid not necessary glyph transformations */
5317 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5319 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5320 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5321 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5326 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5327 font scaling abilities. */
5328 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5329 dcmat
.eM21
= dcmat
.eM12
= 0;
5330 lf
.lfOrientation
= lf
.lfEscapement
;
5331 if (dc
->vport2WorldValid
)
5333 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5334 lf
.lfOrientation
= -lf
.lfOrientation
;
5335 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5336 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5340 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5341 dcmat
.eM21
, dcmat
.eM22
);
5344 EnterCriticalSection( &freetype_cs
);
5346 /* check the cache first */
5347 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5348 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5352 TRACE("not in cache\n");
5355 ret
->font_desc
.matrix
= dcmat
;
5356 ret
->font_desc
.lf
= lf
;
5357 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5358 calc_hash(&ret
->font_desc
);
5360 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5361 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5362 original value lfCharSet. Note this is a special case for
5363 Symbol and doesn't happen at least for "Wingdings*" */
5365 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5366 lf
.lfCharSet
= SYMBOL_CHARSET
;
5368 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5369 switch(lf
.lfCharSet
) {
5370 case DEFAULT_CHARSET
:
5371 csi
.fs
.fsCsb
[0] = 0;
5374 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5375 csi
.fs
.fsCsb
[0] = 0;
5381 if(lf
.lfFaceName
[0] != '\0') {
5382 CHILD_FONT
*font_link_entry
;
5383 LPWSTR FaceName
= lf
.lfFaceName
;
5385 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5388 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5389 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5390 if (psub
->to
.charset
!= -1)
5391 lf
.lfCharSet
= psub
->to
.charset
;
5394 /* We want a match on name and charset or just name if
5395 charset was DEFAULT_CHARSET. If the latter then
5396 we fixup the returned charset later in get_nearest_charset
5397 where we'll either use the charset of the current ansi codepage
5398 or if that's unavailable the first charset that the font supports.
5400 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5401 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5402 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5404 font_link
= find_font_link(family
->FamilyName
);
5405 face_list
= get_face_list_from_family(family
);
5406 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5407 if (!(face
->scalable
|| can_use_bitmap
))
5409 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5411 if (font_link
!= NULL
&&
5412 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5414 if (!csi
.fs
.fsCsb
[0])
5420 /* Search by full face name. */
5421 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5422 face_list
= get_face_list_from_family(family
);
5423 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5424 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5425 (face
->scalable
|| can_use_bitmap
))
5427 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5429 font_link
= find_font_link(family
->FamilyName
);
5430 if (font_link
!= NULL
&&
5431 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5438 * Try check the SystemLink list first for a replacement font.
5439 * We may find good replacements there.
5441 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5443 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5444 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5446 TRACE("found entry in system list\n");
5447 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5449 const SYSTEM_LINKS
*links
;
5451 face
= font_link_entry
->face
;
5452 if (!(face
->scalable
|| can_use_bitmap
))
5454 family
= face
->family
;
5455 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5457 links
= find_font_link(family
->FamilyName
);
5458 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5465 psub
= NULL
; /* substitution is no more relevant */
5467 /* If requested charset was DEFAULT_CHARSET then try using charset
5468 corresponding to the current ansi codepage */
5469 if (!csi
.fs
.fsCsb
[0])
5472 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5473 FIXME("TCI failed on codepage %d\n", acp
);
5474 csi
.fs
.fsCsb
[0] = 0;
5476 lf
.lfCharSet
= csi
.ciCharset
;
5479 want_vertical
= (lf
.lfFaceName
[0] == '@');
5481 /* Face families are in the top 4 bits of lfPitchAndFamily,
5482 so mask with 0xF0 before testing */
5484 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5485 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5486 strcpyW(lf
.lfFaceName
, defFixed
);
5487 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5488 strcpyW(lf
.lfFaceName
, defSerif
);
5489 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5490 strcpyW(lf
.lfFaceName
, defSans
);
5492 strcpyW(lf
.lfFaceName
, defSans
);
5493 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5494 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5495 font_link
= find_font_link(family
->FamilyName
);
5496 face_list
= get_face_list_from_family(family
);
5497 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5498 if (!(face
->scalable
|| can_use_bitmap
))
5500 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5502 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5508 last_resort_family
= NULL
;
5509 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5510 font_link
= find_font_link(family
->FamilyName
);
5511 face_list
= get_face_list_from_family(family
);
5512 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5513 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5514 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5515 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5518 if(can_use_bitmap
&& !last_resort_family
)
5519 last_resort_family
= family
;
5524 if(last_resort_family
) {
5525 family
= last_resort_family
;
5526 csi
.fs
.fsCsb
[0] = 0;
5530 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5531 face_list
= get_face_list_from_family(family
);
5532 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5533 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5534 csi
.fs
.fsCsb
[0] = 0;
5535 WARN("just using first face for now\n");
5538 if(can_use_bitmap
&& !last_resort_family
)
5539 last_resort_family
= family
;
5542 if(!last_resort_family
) {
5543 FIXME("can't find a single appropriate font - bailing\n");
5549 WARN("could only find a bitmap font - this will probably look awful!\n");
5550 family
= last_resort_family
;
5551 csi
.fs
.fsCsb
[0] = 0;
5554 it
= lf
.lfItalic
? 1 : 0;
5555 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5557 height
= lf
.lfHeight
;
5559 face
= best
= best_bitmap
= NULL
;
5560 font_link
= find_font_link(family
->FamilyName
);
5561 face_list
= get_face_list_from_family(family
);
5562 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5564 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5565 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5570 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5571 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5572 new_score
= (italic
^ it
) + (bold
^ bd
);
5573 if(!best
|| new_score
<= score
)
5575 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5576 italic
, bold
, it
, bd
);
5579 if(best
->scalable
&& score
== 0) break;
5583 newdiff
= height
- (signed int)(best
->size
.height
);
5585 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5586 if(!best_bitmap
|| new_score
< score
||
5587 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5589 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5592 if(score
== 0 && diff
== 0) break;
5599 face
= best
->scalable
? best
: best_bitmap
;
5600 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5601 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5604 height
= lf
.lfHeight
;
5608 if(csi
.fs
.fsCsb
[0]) {
5609 ret
->charset
= lf
.lfCharSet
;
5610 ret
->codepage
= csi
.ciACP
;
5613 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5615 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5616 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5618 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5620 if(!face
->scalable
) {
5621 /* Windows uses integer scaling factors for bitmap fonts */
5622 INT scale
, scaled_height
;
5623 GdiFont
*cachedfont
;
5625 /* FIXME: rotation of bitmap fonts is ignored */
5626 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5628 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5629 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5630 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5631 /* As we changed the matrix, we need to search the cache for the font again,
5632 * otherwise we might explode the cache. */
5633 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5634 TRACE("Found cached font after non-scalable matrix rescale!\n");
5639 calc_hash(&ret
->font_desc
);
5641 if (height
!= 0) height
= diff
;
5642 height
+= face
->size
.height
;
5644 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5645 scaled_height
= scale
* face
->size
.height
;
5646 /* Only jump to the next height if the difference <= 25% original height */
5647 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5648 /* The jump between unscaled and doubled is delayed by 1 */
5649 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5650 ret
->scale_y
= scale
;
5652 width
= face
->size
.x_ppem
>> 6;
5653 height
= face
->size
.y_ppem
>> 6;
5657 TRACE("font scale y: %f\n", ret
->scale_y
);
5659 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5668 fill_fileinfo_from_face( ret
, face
);
5669 ret
->ntmFlags
= face
->ntmFlags
;
5671 pick_charmap( ret
->ft_face
, ret
->charset
);
5673 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5674 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5675 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5676 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5677 create_child_font_list(ret
);
5679 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5681 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5682 if (length
!= GDI_ERROR
)
5684 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5685 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5686 TRACE("Loaded GSUB table of %i bytes\n",length
);
5687 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5688 if (!ret
->vert_feature
)
5690 TRACE("Vertical feature not found\n");
5691 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5692 ret
->GSUB_Table
= NULL
;
5696 ret
->aa_flags
= HIWORD( face
->flags
);
5698 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5704 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5706 switch (lf
.lfQuality
)
5708 case NONANTIALIASED_QUALITY
:
5709 case ANTIALIASED_QUALITY
:
5710 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5712 case CLEARTYPE_QUALITY
:
5713 case CLEARTYPE_NATURAL_QUALITY
:
5715 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5716 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5718 /* fixup the antialiasing flags for that font */
5721 case WINE_GGO_HRGB_BITMAP
:
5722 case WINE_GGO_HBGR_BITMAP
:
5723 case WINE_GGO_VRGB_BITMAP
:
5724 case WINE_GGO_VBGR_BITMAP
:
5725 if (is_subpixel_rendering_enabled()) break;
5726 *aa_flags
= GGO_GRAY4_BITMAP
;
5728 case GGO_GRAY2_BITMAP
:
5729 case GGO_GRAY4_BITMAP
:
5730 case GGO_GRAY8_BITMAP
:
5731 case WINE_GGO_GRAY16_BITMAP
:
5732 if ((!antialias_fakes
|| (!ret
->fake_bold
&& !ret
->fake_italic
)) && is_hinting_enabled())
5735 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5737 TRACE( "font %s %d aa disabled by GASP\n",
5738 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5739 *aa_flags
= GGO_BITMAP
;
5744 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5745 release_font( physdev
->font
);
5746 physdev
->font
= ret
;
5748 LeaveCriticalSection( &freetype_cs
);
5749 release_dc_ptr( dc
);
5750 return ret
? hfont
: 0;
5753 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5760 id
+= IDS_FIRST_SCRIPT
;
5761 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5762 if (!rsrc
) return 0;
5763 hMem
= LoadResource( gdi32_module
, rsrc
);
5764 if (!hMem
) return 0;
5766 p
= LockResource( hMem
);
5768 while (id
--) p
+= *p
+ 1;
5770 i
= min(LF_FACESIZE
- 1, *p
);
5771 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5776 static inline BOOL
is_complex_script_ansi_cp(UINT ansi_cp
)
5778 return (ansi_cp
== 874 /* Thai */
5779 || ansi_cp
== 1255 /* Hebrew */
5780 || ansi_cp
== 1256 /* Arabic */
5784 /***************************************************
5785 * create_enum_charset_list
5787 * This function creates charset enumeration list because in DEFAULT_CHARSET
5788 * case, the ANSI codepage's charset takes precedence over other charsets.
5789 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5790 * This function works as a filter other than DEFAULT_CHARSET case.
5792 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5797 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5798 csi
.fs
.fsCsb
[0] != 0) {
5799 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5800 list
->element
[n
].charset
= csi
.ciCharset
;
5801 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5804 else { /* charset is DEFAULT_CHARSET or invalid. */
5808 /* Set the current codepage's charset as the first element. */
5810 if (!is_complex_script_ansi_cp(acp
) &&
5811 TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5812 csi
.fs
.fsCsb
[0] != 0) {
5813 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5814 list
->element
[n
].charset
= csi
.ciCharset
;
5815 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5816 mask
|= csi
.fs
.fsCsb
[0];
5820 /* Fill out left elements. */
5821 for (i
= 0; i
< 32; i
++) {
5823 fs
.fsCsb
[0] = 1L << i
;
5825 if (fs
.fsCsb
[0] & mask
)
5826 continue; /* skip, already added. */
5827 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5828 continue; /* skip, this is an invalid fsCsb bit. */
5830 list
->element
[n
].mask
= fs
.fsCsb
[0];
5831 list
->element
[n
].charset
= csi
.ciCharset
;
5832 load_script_name( i
, list
->element
[n
].name
);
5833 mask
|= fs
.fsCsb
[0];
5837 /* add catch all mask for remaining bits */
5840 list
->element
[n
].mask
= ~mask
;
5841 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5842 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5851 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5852 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5857 if (face
->cached_enum_data
)
5860 *pelf
= face
->cached_enum_data
->elf
;
5861 *pntm
= face
->cached_enum_data
->ntm
;
5862 *ptype
= face
->cached_enum_data
->type
;
5866 font
= alloc_font();
5868 if(face
->scalable
) {
5872 height
= face
->size
.y_ppem
>> 6;
5873 width
= face
->size
.x_ppem
>> 6;
5875 font
->scale_y
= 1.0;
5877 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5883 font
->name
= strdupW( family_name
);
5884 font
->ntmFlags
= face
->ntmFlags
;
5886 if (get_outline_text_metrics(font
))
5888 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5890 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5891 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5892 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5894 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5895 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5897 lstrcpynW(pelf
->elfFullName
,
5898 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5900 lstrcpynW(pelf
->elfStyle
,
5901 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5906 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5908 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5909 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5910 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5912 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5914 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5916 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5917 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5920 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5921 pntm
->ntmFontSig
= face
->fs
;
5923 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5925 pelf
->elfLogFont
.lfEscapement
= 0;
5926 pelf
->elfLogFont
.lfOrientation
= 0;
5927 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5928 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5929 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5930 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5931 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5932 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5933 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5934 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5935 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5936 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5937 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5940 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5941 *ptype
|= TRUETYPE_FONTTYPE
;
5942 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5943 *ptype
|= DEVICE_FONTTYPE
;
5944 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5945 *ptype
|= RASTER_FONTTYPE
;
5947 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5948 if (face
->cached_enum_data
)
5950 face
->cached_enum_data
->elf
= *pelf
;
5951 face
->cached_enum_data
->ntm
= *pntm
;
5952 face
->cached_enum_data
->type
= *ptype
;
5958 static BOOL
family_matches(Family
*family
, const WCHAR
*face_name
)
5961 const struct list
*face_list
;
5963 if (!strcmpiW(face_name
, family
->FamilyName
)) return TRUE
;
5965 face_list
= get_face_list_from_family(family
);
5966 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5967 if (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
)) return TRUE
;
5972 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const WCHAR
*face_name
)
5974 if (!strcmpiW(face_name
, family_name
)) return TRUE
;
5976 return (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
));
5979 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5980 FONTENUMPROCW proc
, LPARAM lparam
, const WCHAR
*subst
)
5983 NEWTEXTMETRICEXW ntm
;
5987 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5988 for(i
= 0; i
< list
->total
; i
++) {
5989 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5990 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5991 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5992 i
= list
->total
; /* break out of loop after enumeration */
5996 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5997 /* use the DEFAULT_CHARSET case only if no other charset is present */
5998 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5999 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
6000 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
6001 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
6002 if (!elf
.elfScript
[0])
6003 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
6005 /* Font Replacement */
6006 if (family
!= face
->family
)
6008 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
6010 strcpyW(elf
.elfFullName
, face
->FullName
);
6012 strcpyW(elf
.elfFullName
, family
->FamilyName
);
6015 strcpyW(elf
.elfLogFont
.lfFaceName
, subst
);
6016 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6017 debugstr_w(elf
.elfLogFont
.lfFaceName
),
6018 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
6019 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
6020 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
6021 ntm
.ntmTm
.ntmFlags
);
6022 /* release section before callback (FIXME) */
6023 LeaveCriticalSection( &freetype_cs
);
6024 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
6025 EnterCriticalSection( &freetype_cs
);
6030 /*************************************************************
6031 * freetype_EnumFonts
6033 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6037 const struct list
*face_list
;
6039 struct enum_charset_list enum_charsets
;
6043 lf
.lfCharSet
= DEFAULT_CHARSET
;
6044 lf
.lfPitchAndFamily
= 0;
6045 lf
.lfFaceName
[0] = 0;
6049 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
6051 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
6054 EnterCriticalSection( &freetype_cs
);
6055 if(plf
->lfFaceName
[0]) {
6056 WCHAR
*face_name
= plf
->lfFaceName
;
6057 FontSubst
*psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
6060 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
6061 debugstr_w(psub
->to
.name
));
6062 face_name
= psub
->to
.name
;
6065 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
6066 if (!family_matches(family
, face_name
)) continue;
6067 face_list
= get_face_list_from_family(family
);
6068 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
6069 if (!face_matches(family
->FamilyName
, face
, face_name
)) continue;
6070 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, psub
? psub
->from
.name
: NULL
)) return FALSE
;
6074 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
6075 face_list
= get_face_list_from_family(family
);
6076 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
6077 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, NULL
)) return FALSE
;
6080 LeaveCriticalSection( &freetype_cs
);
6084 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
6086 pt
->x
.value
= vec
->x
>> 6;
6087 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
6088 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
6089 pt
->y
.value
= vec
->y
>> 6;
6090 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
6091 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
6094 /***************************************************
6095 * According to the MSDN documentation on WideCharToMultiByte,
6096 * certain codepages cannot set the default_used parameter.
6097 * This returns TRUE if the codepage can set that parameter, false else
6098 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6100 static BOOL
codepage_sets_default_used(UINT codepage
)
6114 * GSUB Table handling functions
6117 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
6119 const GSUB_CoverageFormat1
* cf1
;
6123 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
6125 int count
= GET_BE_WORD(cf1
->GlyphCount
);
6127 TRACE("Coverage Format 1, %i glyphs\n",count
);
6128 for (i
= 0; i
< count
; i
++)
6129 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
6133 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
6135 const GSUB_CoverageFormat2
* cf2
;
6138 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
6140 count
= GET_BE_WORD(cf2
->RangeCount
);
6141 TRACE("Coverage Format 2, %i ranges\n",count
);
6142 for (i
= 0; i
< count
; i
++)
6144 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
6146 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
6147 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
6149 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
6150 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
6156 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
6161 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
6165 const GSUB_LookupList
*lookup
;
6166 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
6168 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
6169 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
6171 const GSUB_LookupTable
*look
;
6172 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
6173 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
6174 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
6175 if (GET_BE_WORD(look
->LookupType
) != 1)
6176 FIXME("We only handle SubType 1\n");
6181 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
6183 const GSUB_SingleSubstFormat1
*ssf1
;
6184 offset
= GET_BE_WORD(look
->SubTable
[j
]);
6185 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
6186 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
6188 int offset
= GET_BE_WORD(ssf1
->Coverage
);
6189 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
6190 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
6192 TRACE(" Glyph 0x%x ->",glyph
);
6193 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
6194 TRACE(" 0x%x\n",glyph
);
6199 const GSUB_SingleSubstFormat2
*ssf2
;
6203 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
6204 offset
= GET_BE_WORD(ssf1
->Coverage
);
6205 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
6206 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
6207 TRACE(" Coverage index %i\n",index
);
6210 TRACE(" Glyph is 0x%x ->",glyph
);
6211 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
6212 TRACE("0x%x\n",glyph
);
6222 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
6224 const GSUB_Header
*header
;
6225 const GSUB_Feature
*feature
;
6227 if (!font
->GSUB_Table
)
6230 header
= font
->GSUB_Table
;
6231 feature
= font
->vert_feature
;
6233 return GSUB_apply_feature(header
, feature
, glyph
);
6236 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
6240 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6241 WCHAR wc
= (WCHAR
)glyph
;
6243 BOOL
*default_used_pointer
;
6246 default_used_pointer
= NULL
;
6247 default_used
= FALSE
;
6248 if (codepage_sets_default_used(font
->codepage
))
6249 default_used_pointer
= &default_used
;
6250 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6252 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6253 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6258 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6259 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6263 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6265 if (glyph
< 0x100) glyph
+= 0xf000;
6266 /* there is a number of old pre-Unicode "broken" TTFs, which
6267 do have symbols at U+00XX instead of U+f0XX */
6268 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6269 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6271 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6276 /* helper for freetype_GetGlyphIndices */
6277 static FT_UInt
get_gdi_glyph_index(const GdiFont
*font
, UINT glyph
)
6279 WCHAR wc
= (WCHAR
)glyph
;
6280 BOOL default_used
= FALSE
;
6281 BOOL
*default_used_pointer
= NULL
;
6285 if(font
->ft_face
->charmap
->encoding
!= FT_ENCODING_NONE
)
6286 return get_glyph_index(font
, glyph
);
6288 if (codepage_sets_default_used(font
->codepage
))
6289 default_used_pointer
= &default_used
;
6290 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
)
6293 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6294 ret
= (unsigned char)wc
;
6299 ret
= (unsigned char)buf
;
6300 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6304 static FT_UInt
get_default_char_index(GdiFont
*font
)
6306 FT_UInt default_char
;
6308 if (FT_IS_SFNT(font
->ft_face
))
6310 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6311 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6316 get_text_metrics(font
, &textm
);
6317 default_char
= textm
.tmDefaultChar
;
6320 return default_char
;
6323 /*************************************************************
6324 * freetype_GetGlyphIndices
6326 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6328 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6331 BOOL got_default
= FALSE
;
6335 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6336 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6339 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6341 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6346 EnterCriticalSection( &freetype_cs
);
6348 for(i
= 0; i
< count
; i
++)
6350 pgi
[i
] = get_gdi_glyph_index(physdev
->font
, lpstr
[i
]);
6355 default_char
= get_default_char_index(physdev
->font
);
6358 pgi
[i
] = default_char
;
6361 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6363 LeaveCriticalSection( &freetype_cs
);
6367 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6369 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6370 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6373 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6375 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6376 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6379 static void synthesize_bold_glyph(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
6384 switch(glyph
->format
) {
6385 case FT_GLYPH_FORMAT_OUTLINE
:
6389 if(!pFT_Outline_Embolden
)
6392 strength
= MulDiv(ppem
, 1 << 6, 24);
6393 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
6395 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err
);
6399 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
6400 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
6401 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
6402 metrics
->horiBearingX
= bbox
.xMin
;
6403 metrics
->horiBearingY
= bbox
.yMax
;
6404 metrics
->horiAdvance
+= (1 << 6);
6405 metrics
->vertAdvance
+= (1 << 6);
6406 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
6407 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
6412 WARN("Emboldening format 0x%x is not supported\n", glyph
->format
);
6417 static inline BYTE
get_max_level( UINT format
)
6421 case GGO_GRAY2_BITMAP
: return 4;
6422 case GGO_GRAY4_BITMAP
: return 16;
6423 case GGO_GRAY8_BITMAP
: return 64;
6428 extern const unsigned short vertical_orientation_table
[];
6430 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6432 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[uchar
>> 8]+((uchar
>> 4) & 0x0f)]+ (uchar
& 0xf)];
6434 /* We only reach this code if typographical substitution did not occur */
6435 /* Type: U or Type: Tu */
6436 return (orientation
== 1 || orientation
== 3);
6439 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6441 TTPOLYGONHEADER
*pph
;
6443 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
6444 unsigned int pph_start
, cpfx
;
6447 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6449 /* Ignore contours containing one point */
6450 if (point
== outline
->contours
[contour
])
6457 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6461 pph
->dwType
= TT_POLYGON_TYPE
;
6462 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6464 needed
+= sizeof(*pph
);
6466 while (point
<= outline
->contours
[contour
])
6468 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6469 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6470 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6475 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6478 } while (point
<= outline
->contours
[contour
] &&
6479 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6480 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6481 /* At the end of a contour Windows adds the start point, but
6483 if (point
> outline
->contours
[contour
] &&
6484 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6487 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6490 else if (point
<= outline
->contours
[contour
] &&
6491 outline
->tags
[point
] & FT_Curve_Tag_On
)
6493 /* add closing pt for bezier */
6495 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6504 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6507 pph
->cb
= needed
- pph_start
;
6512 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6514 /* Convert the quadratic Beziers to cubic Beziers.
6515 The parametric eqn for a cubic Bezier is, from PLRM:
6516 r(t) = at^3 + bt^2 + ct + r0
6517 with the control points:
6522 A quadratic Bezier has the form:
6523 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6525 So equating powers of t leads to:
6526 r1 = 2/3 p1 + 1/3 p0
6527 r2 = 2/3 p1 + 1/3 p2
6528 and of course r0 = p0, r3 = p2
6530 int contour
, point
= 0, first_pt
;
6531 TTPOLYGONHEADER
*pph
;
6533 DWORD pph_start
, cpfx
, type
;
6534 FT_Vector cubic_control
[4];
6535 unsigned int needed
= 0;
6537 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6540 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6544 pph
->dwType
= TT_POLYGON_TYPE
;
6545 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6547 needed
+= sizeof(*pph
);
6549 while (point
<= outline
->contours
[contour
])
6551 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6552 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6553 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6557 if (type
== TT_PRIM_LINE
)
6560 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6566 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6569 /* FIXME: Possible optimization in endpoint calculation
6570 if there are two consecutive curves */
6571 cubic_control
[0] = outline
->points
[point
-1];
6572 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6574 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6575 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6576 cubic_control
[0].x
>>= 1;
6577 cubic_control
[0].y
>>= 1;
6579 if (point
+1 > outline
->contours
[contour
])
6580 cubic_control
[3] = outline
->points
[first_pt
];
6583 cubic_control
[3] = outline
->points
[point
+1];
6584 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
6586 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6587 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6588 cubic_control
[3].x
>>= 1;
6589 cubic_control
[3].y
>>= 1;
6592 /* r1 = 1/3 p0 + 2/3 p1
6593 r2 = 1/3 p2 + 2/3 p1 */
6594 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6595 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6596 cubic_control
[2] = cubic_control
[1];
6597 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6598 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6599 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6600 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6603 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6604 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6605 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6610 } while (point
<= outline
->contours
[contour
] &&
6611 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6612 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6613 /* At the end of a contour Windows adds the start point,
6614 but only for Beziers and we've already done that.
6616 if (point
<= outline
->contours
[contour
] &&
6617 outline
->tags
[point
] & FT_Curve_Tag_On
)
6619 /* This is the closing pt of a bezier, but we've already
6620 added it, so just inc point and carry on */
6628 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6631 pph
->cb
= needed
- pph_start
;
6636 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6638 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6639 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6642 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6644 FT_Face ft_face
= incoming_font
->ft_face
;
6645 GdiFont
*font
= incoming_font
;
6646 FT_Glyph_Metrics metrics
;
6647 FT_UInt glyph_index
;
6648 DWORD width
, height
, pitch
, needed
= 0;
6649 FT_Bitmap ft_bitmap
;
6651 INT left
, right
, top
= 0, bottom
= 0, adv
;
6652 INT origin_x
= 0, origin_y
= 0;
6654 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6655 double widthRatio
= 1.0;
6656 FT_Matrix transMat
= identityMat
;
6657 FT_Matrix transMatUnrotated
;
6658 FT_Matrix transMatTategaki
;
6659 BOOL needsTransform
= FALSE
;
6660 BOOL tategaki
= (font
->name
[0] == '@');
6661 BOOL vertical_metrics
;
6662 UINT original_index
;
6663 LONG avgAdvance
= 0;
6666 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6667 buflen
, buf
, lpmat
);
6669 TRACE("font transform %f %f %f %f\n",
6670 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6671 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6673 if(format
& GGO_GLYPH_INDEX
) {
6674 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6675 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6676 as glyph index. "Treasure Adventure Game" depends on this. */
6677 glyph_index
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6678 TRACE("translate glyph index %04x -> %04x\n", glyph
, glyph_index
);
6680 glyph_index
= glyph
;
6681 original_index
= glyph_index
;
6682 format
&= ~GGO_GLYPH_INDEX
;
6683 /* TODO: Window also turns off tategaki for glyphs passed in by index
6684 if their unicode code points fall outside of the range that is
6688 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6689 ft_face
= font
->ft_face
;
6690 original_index
= glyph_index
;
6691 if (!vert
&& tategaki
)
6692 tategaki
= check_unicode_tategaki(glyph
);
6695 if(format
& GGO_UNHINTED
) {
6696 load_flags
|= FT_LOAD_NO_HINTING
;
6697 format
&= ~GGO_UNHINTED
;
6700 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6701 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6702 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6703 font
->gmsize
* sizeof(GM
*));
6705 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6706 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6708 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6709 *abc
= FONT_GM(font
,original_index
)->abc
;
6710 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6711 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6712 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6713 return 1; /* FIXME */
6717 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6718 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6720 /* Scaling factor */
6725 get_text_metrics(font
, &tm
);
6727 widthRatio
= (double)font
->aveWidth
;
6728 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6731 widthRatio
= font
->scale_y
;
6733 /* Scaling transform */
6734 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6737 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6740 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6742 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6743 needsTransform
= TRUE
;
6746 /* Slant transform */
6747 if (font
->fake_italic
) {
6750 slantMat
.xx
= (1 << 16);
6751 slantMat
.xy
= ((1 << 16) >> 2);
6753 slantMat
.yy
= (1 << 16);
6754 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6755 needsTransform
= TRUE
;
6758 /* Rotation transform */
6759 transMatUnrotated
= transMat
;
6760 transMatTategaki
= transMat
;
6761 if(font
->orientation
|| tategaki
) {
6762 FT_Matrix rotationMat
;
6763 FT_Matrix taterotationMat
;
6766 double orient
= font
->orientation
/ 10.0;
6767 double tate_orient
= 0.f
;
6770 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6772 tate_orient
= font
->orientation
/10.0;
6776 angle
= FT_FixedFromFloat(orient
);
6777 pFT_Vector_Unit(&vecAngle
, angle
);
6778 rotationMat
.xx
= vecAngle
.x
;
6779 rotationMat
.xy
= -vecAngle
.y
;
6780 rotationMat
.yx
= -rotationMat
.xy
;
6781 rotationMat
.yy
= rotationMat
.xx
;
6783 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6788 angle
= FT_FixedFromFloat(tate_orient
);
6789 pFT_Vector_Unit(&vecAngle
, angle
);
6790 taterotationMat
.xx
= vecAngle
.x
;
6791 taterotationMat
.xy
= -vecAngle
.y
;
6792 taterotationMat
.yx
= -taterotationMat
.xy
;
6793 taterotationMat
.yy
= taterotationMat
.xx
;
6794 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6797 needsTransform
= TRUE
;
6800 /* World transform */
6801 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6804 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6805 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6806 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6807 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6808 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6809 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6810 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6811 needsTransform
= TRUE
;
6814 /* Extra transformation specified by caller */
6815 if (!is_identity_MAT2(lpmat
))
6818 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6819 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6820 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6821 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6822 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6823 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6824 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6825 needsTransform
= TRUE
;
6828 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6829 /* there is a freetype bug where vertical metrics are only
6830 properly scaled and correct in 2.4.0 or greater */
6831 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6832 vertical_metrics
= FALSE
;
6834 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6835 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6837 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6840 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6844 metrics
= ft_face
->glyph
->metrics
;
6846 synthesize_bold_glyph(ft_face
->glyph
, font
->ppem
, &metrics
);
6848 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6849 * by the text metrics. The proper behavior is to clip the glyph metrics to
6850 * fit within the maximums specified in the text metrics. */
6851 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6852 get_bitmap_text_metrics(incoming_font
)) {
6853 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6854 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6855 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6856 metrics
.horiBearingY
= top
;
6857 metrics
.height
= top
- bottom
;
6859 /* TODO: Are we supposed to clip the width as well...? */
6860 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6863 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6865 if(FT_IS_SCALABLE(incoming_font
->ft_face
) && !font
->fake_bold
) {
6867 if (get_text_metrics(incoming_font
, &tm
) &&
6868 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6869 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6871 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6872 TRACE("Fixed-pitch full-width character detected\n");
6874 avgAdvance
= 0; /* cancel this feature */
6878 if(!needsTransform
) {
6879 left
= (INT
)(metrics
.horiBearingX
) & -64;
6880 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6882 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6884 adv
= (INT
)avgAdvance
* 2;
6886 top
= (metrics
.horiBearingY
+ 63) & -64;
6887 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6888 gm
.gmCellIncX
= adv
;
6892 abc
->abcA
= origin_x
>> 6;
6893 abc
->abcB
= metrics
.width
>> 6;
6901 for(xc
= 0; xc
< 2; xc
++) {
6902 for(yc
= 0; yc
< 2; yc
++) {
6903 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6904 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6905 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6906 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6907 if(xc
== 0 && yc
== 0) {
6908 left
= right
= vec
.x
;
6909 top
= bottom
= vec
.y
;
6911 if(vec
.x
< left
) left
= vec
.x
;
6912 else if(vec
.x
> right
) right
= vec
.x
;
6913 if(vec
.y
< bottom
) bottom
= vec
.y
;
6914 else if(vec
.y
> top
) top
= vec
.y
;
6919 right
= (right
+ 63) & -64;
6920 bottom
= bottom
& -64;
6921 top
= (top
+ 63) & -64;
6923 if (tategaki
&& (font
->potm
|| get_outline_text_metrics(font
)))
6925 if (vertical_metrics
)
6926 lsb
= metrics
.horiBearingY
+ metrics
.vertBearingY
;
6928 lsb
= metrics
.vertAdvance
+ (font
->potm
->otmDescent
<< 6);
6930 vec
.y
= font
->potm
->otmDescent
<< 6;
6931 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
6932 pFT_Vector_Transform(&vec
, &transMat
);
6933 origin_x
= (vec
.x
+ left
) & -64;
6934 origin_y
= (vec
.y
+ top
+ 63) & -64;
6940 lsb
= metrics
.horiBearingX
;
6943 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6944 if (vertical_metrics
)
6945 vec
.x
= metrics
.vertAdvance
;
6947 vec
.x
= metrics
.horiAdvance
;
6949 pFT_Vector_Transform(&vec
, &transMat
);
6950 gm
.gmCellIncY
= -((vec
.y
+63) >> 6);
6951 if (!avgAdvance
|| vec
.y
)
6952 gm
.gmCellIncX
= (vec
.x
+63) >> 6;
6954 vec
.x
= incoming_font
->ntmAvgWidth
;
6956 pFT_Vector_Transform(&vec
, &transMat
);
6957 gm
.gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6960 if (vertical_metrics
)
6961 vec
.x
= metrics
.vertAdvance
;
6963 vec
.x
= metrics
.horiAdvance
;
6965 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6966 if (!avgAdvance
|| vec
.y
)
6967 adv
= (vec
.x
+63) >> 6;
6969 vec
.x
= incoming_font
->ntmAvgWidth
;
6971 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6972 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6977 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6978 abc
->abcA
= vec
.x
>> 6;
6980 vec
.x
= metrics
.width
;
6982 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6984 abc
->abcB
= vec
.x
>> 6;
6986 abc
->abcB
= -vec
.x
>> 6;
6989 width
= (right
- left
) >> 6;
6990 height
= (top
- bottom
) >> 6;
6991 gm
.gmBlackBoxX
= width
? width
: 1;
6992 gm
.gmBlackBoxY
= height
? height
: 1;
6993 gm
.gmptGlyphOrigin
.x
= origin_x
>> 6;
6994 gm
.gmptGlyphOrigin
.y
= origin_y
>> 6;
6995 if (!abc
->abcB
) abc
->abcB
= 1;
6996 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6998 TRACE("%u,%u,%s,%d,%d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
6999 wine_dbgstr_point(&gm
.gmptGlyphOrigin
),
7000 gm
.gmCellIncX
, gm
.gmCellIncY
);
7002 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
7003 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
7005 FONT_GM(font
,original_index
)->gm
= gm
;
7006 FONT_GM(font
,original_index
)->abc
= *abc
;
7007 FONT_GM(font
,original_index
)->init
= TRUE
;
7010 if(format
== GGO_METRICS
)
7013 return 1; /* FIXME */
7016 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
7017 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
7019 TRACE("loaded a bitmap\n");
7025 pitch
= ((width
+ 31) >> 5) << 2;
7026 needed
= pitch
* height
;
7028 if(!buf
|| !buflen
) break;
7029 if (!needed
) return GDI_ERROR
; /* empty glyph */
7030 if (needed
> buflen
)
7033 switch(ft_face
->glyph
->format
) {
7034 case ft_glyph_format_bitmap
:
7036 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
7037 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
7038 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7040 memcpy(dst
, src
, w
);
7041 src
+= ft_face
->glyph
->bitmap
.pitch
;
7047 case ft_glyph_format_outline
:
7048 ft_bitmap
.width
= width
;
7049 ft_bitmap
.rows
= height
;
7050 ft_bitmap
.pitch
= pitch
;
7051 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
7052 ft_bitmap
.buffer
= buf
;
7055 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
7057 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
7059 /* Note: FreeType will only set 'black' bits for us. */
7060 memset(buf
, 0, needed
);
7061 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
7065 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
7070 case GGO_GRAY2_BITMAP
:
7071 case GGO_GRAY4_BITMAP
:
7072 case GGO_GRAY8_BITMAP
:
7073 case WINE_GGO_GRAY16_BITMAP
:
7075 unsigned int max_level
, row
, col
;
7078 pitch
= (width
+ 3) / 4 * 4;
7079 needed
= pitch
* height
;
7081 if(!buf
|| !buflen
) break;
7082 if (!needed
) return GDI_ERROR
; /* empty glyph */
7083 if (needed
> buflen
)
7086 max_level
= get_max_level( format
);
7088 switch(ft_face
->glyph
->format
) {
7089 case ft_glyph_format_bitmap
:
7091 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
7092 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7094 memset( buf
, 0, needed
);
7096 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
7097 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
7098 src
+= ft_face
->glyph
->bitmap
.pitch
;
7103 case ft_glyph_format_outline
:
7105 ft_bitmap
.width
= width
;
7106 ft_bitmap
.rows
= height
;
7107 ft_bitmap
.pitch
= pitch
;
7108 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
7109 ft_bitmap
.buffer
= buf
;
7112 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
7114 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
7116 memset(ft_bitmap
.buffer
, 0, buflen
);
7118 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
7120 if (max_level
!= 255)
7122 for (row
= 0, start
= buf
; row
< height
; row
++)
7124 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
7125 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
7133 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
7139 case WINE_GGO_HRGB_BITMAP
:
7140 case WINE_GGO_HBGR_BITMAP
:
7141 case WINE_GGO_VRGB_BITMAP
:
7142 case WINE_GGO_VBGR_BITMAP
:
7143 #ifdef FT_LCD_FILTER_H
7145 switch (ft_face
->glyph
->format
)
7147 case FT_GLYPH_FORMAT_BITMAP
:
7153 needed
= pitch
* height
;
7155 if (!buf
|| !buflen
) break;
7156 if (!needed
) return GDI_ERROR
; /* empty glyph */
7157 if (needed
> buflen
)
7160 memset(buf
, 0, buflen
);
7162 src
= ft_face
->glyph
->bitmap
.buffer
;
7163 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7165 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7168 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
7170 if ( src
[x
/ 8] & masks
[x
% 8] )
7171 ((unsigned int *)dst
)[x
] = ~0u;
7180 case FT_GLYPH_FORMAT_OUTLINE
:
7184 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
7185 INT x_shift
, y_shift
;
7187 FT_Render_Mode render_mode
=
7188 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
7189 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
7191 if (!width
|| !height
)
7193 if (!buf
|| !buflen
) break;
7197 if ( render_mode
== FT_RENDER_MODE_LCD
)
7199 gm
.gmBlackBoxX
+= 2;
7200 gm
.gmptGlyphOrigin
.x
-= 1;
7205 gm
.gmBlackBoxY
+= 2;
7206 gm
.gmptGlyphOrigin
.y
+= 1;
7210 width
= gm
.gmBlackBoxX
;
7211 height
= gm
.gmBlackBoxY
;
7213 needed
= pitch
* height
;
7215 if (!buf
|| !buflen
) break;
7216 if (needed
> buflen
)
7219 memset(buf
, 0, buflen
);
7221 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
7223 if ( needsTransform
)
7224 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
7226 if ( pFT_Library_SetLcdFilter
)
7227 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
7228 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
7230 src
= ft_face
->glyph
->bitmap
.buffer
;
7231 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7232 src_width
= ft_face
->glyph
->bitmap
.width
;
7233 src_height
= ft_face
->glyph
->bitmap
.rows
;
7235 if ( render_mode
== FT_RENDER_MODE_LCD
)
7243 rgb_interval
= src_pitch
;
7248 x_shift
= ft_face
->glyph
->bitmap_left
- (left
>> 6);
7251 src
+= hmul
* -x_shift
;
7252 src_width
-= hmul
* -x_shift
;
7254 else if ( x_shift
> 0 )
7260 y_shift
= (top
>> 6) - ft_face
->glyph
->bitmap_top
;
7263 src
+= src_pitch
* vmul
* -y_shift
;
7264 src_height
-= vmul
* -y_shift
;
7266 else if ( y_shift
> 0 )
7268 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
7272 width
= min( width
, src_width
/ hmul
);
7273 height
= min( height
, src_height
/ vmul
);
7277 for ( x
= 0; x
< width
; x
++ )
7281 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
7282 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7283 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
7284 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7288 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
7289 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7290 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
7291 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7294 src
+= src_pitch
* vmul
;
7295 dst
+= pitch
/ sizeof(*dst
);
7302 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
7314 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7316 if(buflen
== 0) buf
= NULL
;
7318 if (needsTransform
&& buf
)
7319 pFT_Outline_Transform(outline
, &transMatTategaki
);
7321 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
7323 if (!buf
|| !buflen
)
7325 if (needed
> buflen
)
7328 get_native_glyph_outline(outline
, buflen
, buf
);
7333 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7334 if(buflen
== 0) buf
= NULL
;
7336 if (needsTransform
&& buf
)
7337 pFT_Outline_Transform(outline
, &transMat
);
7339 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
7341 if (!buf
|| !buflen
)
7343 if (needed
> buflen
)
7346 get_bezier_glyph_outline(outline
, buflen
, buf
);
7351 FIXME("Unsupported format %d\n", format
);
7358 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7360 FT_Face ft_face
= font
->ft_face
;
7361 FT_WinFNT_HeaderRec winfnt_header
;
7362 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7363 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7364 font
->potm
->otmSize
= size
;
7366 #define TM font->potm->otmTextMetrics
7367 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7369 TM
.tmHeight
= winfnt_header
.pixel_height
;
7370 TM
.tmAscent
= winfnt_header
.ascent
;
7371 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7372 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7373 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7374 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7375 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7376 TM
.tmWeight
= winfnt_header
.weight
;
7378 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7379 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7380 TM
.tmFirstChar
= winfnt_header
.first_char
;
7381 TM
.tmLastChar
= winfnt_header
.last_char
;
7382 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7383 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7384 TM
.tmItalic
= winfnt_header
.italic
;
7385 TM
.tmUnderlined
= font
->underline
;
7386 TM
.tmStruckOut
= font
->strikeout
;
7387 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7388 TM
.tmCharSet
= winfnt_header
.charset
;
7392 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7393 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7394 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7395 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7396 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7397 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7398 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7399 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7401 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7402 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7404 TM
.tmLastChar
= 255;
7405 TM
.tmDefaultChar
= 32;
7406 TM
.tmBreakChar
= 32;
7407 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7408 TM
.tmUnderlined
= font
->underline
;
7409 TM
.tmStruckOut
= font
->strikeout
;
7410 /* NB inverted meaning of TMPF_FIXED_PITCH */
7411 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
7412 TM
.tmCharSet
= font
->charset
;
7420 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7422 double scale_x
, scale_y
;
7426 scale_x
= (double)font
->aveWidth
;
7427 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7430 scale_x
= font
->scale_y
;
7432 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7433 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7435 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7436 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7438 SCALE_Y(ptm
->tmHeight
);
7439 SCALE_Y(ptm
->tmAscent
);
7440 SCALE_Y(ptm
->tmDescent
);
7441 SCALE_Y(ptm
->tmInternalLeading
);
7442 SCALE_Y(ptm
->tmExternalLeading
);
7443 SCALE_Y(ptm
->tmOverhang
);
7445 SCALE_X(ptm
->tmAveCharWidth
);
7446 SCALE_X(ptm
->tmMaxCharWidth
);
7452 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7454 double scale_x
, scale_y
;
7458 scale_x
= (double)font
->aveWidth
;
7459 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7462 scale_x
= font
->scale_y
;
7464 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7465 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7467 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7469 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7470 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7472 SCALE_Y(potm
->otmAscent
);
7473 SCALE_Y(potm
->otmDescent
);
7474 SCALE_Y(potm
->otmLineGap
);
7475 SCALE_Y(potm
->otmsCapEmHeight
);
7476 SCALE_Y(potm
->otmsXHeight
);
7477 SCALE_Y(potm
->otmrcFontBox
.top
);
7478 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7479 SCALE_X(potm
->otmrcFontBox
.left
);
7480 SCALE_X(potm
->otmrcFontBox
.right
);
7481 SCALE_Y(potm
->otmMacAscent
);
7482 SCALE_Y(potm
->otmMacDescent
);
7483 SCALE_Y(potm
->otmMacLineGap
);
7484 SCALE_X(potm
->otmptSubscriptSize
.x
);
7485 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7486 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7487 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7488 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7489 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7490 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7491 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7492 SCALE_Y(potm
->otmsStrikeoutSize
);
7493 SCALE_Y(potm
->otmsStrikeoutPosition
);
7494 SCALE_Y(potm
->otmsUnderscoreSize
);
7495 SCALE_Y(potm
->otmsUnderscorePosition
);
7501 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7505 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7507 /* Make sure that the font has sane width/height ratio */
7510 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7512 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7517 *ptm
= font
->potm
->otmTextMetrics
;
7518 scale_font_metrics(font
, ptm
);
7522 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7526 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7528 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7534 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7537 FT_Face ft_face
= font
->ft_face
;
7538 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7540 TT_HoriHeader
*pHori
;
7541 TT_Postscript
*pPost
;
7543 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7545 INT ascent
, descent
;
7548 TRACE("font=%p\n", font
);
7550 if(!FT_IS_SCALABLE(ft_face
))
7553 needed
= sizeof(*font
->potm
);
7555 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7556 family_nameW
= strdupW(font
->name
);
7558 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7561 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7562 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7564 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7566 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7569 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7570 face_nameW
= strdupW(font
->name
);
7572 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7573 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7575 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7578 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7579 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7580 full_nameW
= strdupW(fake_nameW
);
7582 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7584 /* These names should be read from the TT name table */
7586 /* length of otmpFamilyName */
7589 /* length of otmpFaceName */
7592 /* length of otmpStyleName */
7595 /* length of otmpFullName */
7599 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7601 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7603 FIXME("Can't find OS/2 table - not TT font?\n");
7607 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7609 FIXME("Can't find HHEA table - not TT font?\n");
7613 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7615 TRACE("OS/2 winA = %u winD = %u typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
7616 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7617 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7618 pOS2
->xAvgCharWidth
,
7619 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7620 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7621 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7623 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7624 font
->potm
->otmSize
= needed
;
7626 #define TM font->potm->otmTextMetrics
7628 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
7629 if(pOS2
->usWinAscent
+ windescent
== 0) {
7630 ascent
= pHori
->Ascender
;
7631 descent
= -pHori
->Descender
;
7633 ascent
= pOS2
->usWinAscent
;
7634 descent
= windescent
;
7637 font
->ntmCellHeight
= ascent
+ descent
;
7638 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7640 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7641 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7644 TM
.tmAscent
= font
->yMax
;
7645 TM
.tmDescent
= -font
->yMin
;
7646 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7648 TM
.tmAscent
= SCALE_Y(ascent
);
7649 TM
.tmDescent
= SCALE_Y(descent
);
7650 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7653 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7656 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7658 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7659 ((ascent
+ descent
) -
7660 (pHori
->Ascender
- pHori
->Descender
))));
7662 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7663 if (TM
.tmAveCharWidth
== 0) {
7664 TM
.tmAveCharWidth
= 1;
7666 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7667 TM
.tmWeight
= FW_REGULAR
;
7668 if (font
->fake_bold
) {
7669 TM
.tmAveCharWidth
++;
7670 TM
.tmMaxCharWidth
++;
7671 TM
.tmWeight
= FW_BOLD
;
7675 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7677 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7678 TM
.tmWeight
= pOS2
->usWeightClass
;
7680 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7681 TM
.tmWeight
= pOS2
->usWeightClass
;
7684 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7685 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7686 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7687 * symbol range to 0 - f0ff
7690 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7695 case 1255: /* Hebrew */
7696 TM
.tmLastChar
= 0xf896;
7698 case 1257: /* Baltic */
7699 TM
.tmLastChar
= 0xf8fd;
7702 TM
.tmLastChar
= 0xf0ff;
7704 TM
.tmBreakChar
= 0x20;
7705 TM
.tmDefaultChar
= 0x1f;
7709 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7710 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7712 if(pOS2
->usFirstCharIndex
<= 1)
7713 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7714 else if (pOS2
->usFirstCharIndex
> 0xff)
7715 TM
.tmBreakChar
= 0x20;
7717 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7718 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7720 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7721 TM
.tmUnderlined
= font
->underline
;
7722 TM
.tmStruckOut
= font
->strikeout
;
7724 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7725 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7726 (pOS2
->version
== 0xFFFFU
||
7727 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7728 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7730 TM
.tmPitchAndFamily
= 0;
7732 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7734 case PAN_FAMILY_SCRIPT
:
7735 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7738 case PAN_FAMILY_DECORATIVE
:
7739 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7744 case PAN_FAMILY_TEXT_DISPLAY
:
7745 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7746 /* which is clearly not what the panose spec says. */
7748 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7749 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7750 TM
.tmPitchAndFamily
= FF_MODERN
;
7753 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7758 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7761 case PAN_SERIF_COVE
:
7762 case PAN_SERIF_OBTUSE_COVE
:
7763 case PAN_SERIF_SQUARE_COVE
:
7764 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7765 case PAN_SERIF_SQUARE
:
7766 case PAN_SERIF_THIN
:
7767 case PAN_SERIF_BONE
:
7768 case PAN_SERIF_EXAGGERATED
:
7769 case PAN_SERIF_TRIANGLE
:
7770 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7773 case PAN_SERIF_NORMAL_SANS
:
7774 case PAN_SERIF_OBTUSE_SANS
:
7775 case PAN_SERIF_PERP_SANS
:
7776 case PAN_SERIF_FLARED
:
7777 case PAN_SERIF_ROUNDED
:
7778 TM
.tmPitchAndFamily
|= FF_SWISS
;
7785 if(FT_IS_SCALABLE(ft_face
))
7786 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7788 if(FT_IS_SFNT(ft_face
))
7790 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7791 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7793 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7796 TM
.tmCharSet
= font
->charset
;
7798 font
->potm
->otmFiller
= 0;
7799 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7800 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7801 font
->potm
->otmfsType
= pOS2
->fsType
;
7802 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7803 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7804 font
->potm
->otmItalicAngle
= 0; /* POST table */
7805 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7806 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7807 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7808 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7809 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7810 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7811 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7812 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7813 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7814 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7815 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7816 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7817 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7818 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7819 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7820 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7821 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7822 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7823 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7824 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7825 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7826 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7827 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7828 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7830 font
->potm
->otmsUnderscoreSize
= 0;
7831 font
->potm
->otmsUnderscorePosition
= 0;
7833 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7834 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7840 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7841 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7842 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7843 strcpyW((WCHAR
*)cp
, family_nameW
);
7845 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7846 strcpyW((WCHAR
*)cp
, style_nameW
);
7848 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7849 strcpyW((WCHAR
*)cp
, face_nameW
);
7851 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7852 strcpyW((WCHAR
*)cp
, full_nameW
);
7856 HeapFree(GetProcessHeap(), 0, style_nameW
);
7857 HeapFree(GetProcessHeap(), 0, family_nameW
);
7858 HeapFree(GetProcessHeap(), 0, face_nameW
);
7859 HeapFree(GetProcessHeap(), 0, full_nameW
);
7863 /*************************************************************
7864 * freetype_GetGlyphOutline
7866 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7867 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7869 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7875 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7876 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7880 EnterCriticalSection( &freetype_cs
);
7881 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7882 LeaveCriticalSection( &freetype_cs
);
7886 /*************************************************************
7887 * freetype_GetTextMetrics
7889 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7891 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7896 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7897 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7901 EnterCriticalSection( &freetype_cs
);
7902 ret
= get_text_metrics( physdev
->font
, metrics
);
7903 LeaveCriticalSection( &freetype_cs
);
7907 /*************************************************************
7908 * freetype_GetOutlineTextMetrics
7910 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7912 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7917 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7918 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7921 TRACE("font=%p\n", physdev
->font
);
7923 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7926 EnterCriticalSection( &freetype_cs
);
7928 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7930 if(potm
&& cbSize
>= physdev
->font
->potm
->otmSize
)
7932 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7933 scale_outline_font_metrics(physdev
->font
, potm
);
7935 ret
= physdev
->font
->potm
->otmSize
;
7937 LeaveCriticalSection( &freetype_cs
);
7941 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7943 child
->font
= alloc_font();
7944 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7945 if(!child
->font
->ft_face
)
7947 free_font(child
->font
);
7952 child
->font
->font_desc
= font
->font_desc
;
7953 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7954 child
->font
->orientation
= font
->orientation
;
7955 child
->font
->scale_y
= font
->scale_y
;
7956 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7957 child
->font
->base_font
= font
;
7958 TRACE("created child font %p for base %p\n", child
->font
, font
);
7962 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
7965 CHILD_FONT
*child_font
;
7968 font
= font
->base_font
;
7970 *linked_font
= font
;
7972 if((*glyph
= get_glyph_index(font
, c
)))
7975 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7976 *vert
= (o
!= *glyph
);
7980 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
7982 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7984 if(!child_font
->font
)
7985 if(!load_child_font(font
, child_font
))
7988 if(!child_font
->font
->ft_face
)
7990 g
= get_glyph_index(child_font
->font
, c
);
7992 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7996 *linked_font
= child_font
->font
;
8007 /*************************************************************
8008 * freetype_GetCharWidth
8010 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
8012 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8016 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8020 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
8021 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
8024 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
8027 EnterCriticalSection( &freetype_cs
);
8028 for(c
= firstChar
; c
<= lastChar
; c
++) {
8029 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
8030 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8032 LeaveCriticalSection( &freetype_cs
);
8036 /*************************************************************
8037 * freetype_GetCharABCWidths
8039 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
8041 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8044 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8048 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
8049 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
8052 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
8055 EnterCriticalSection( &freetype_cs
);
8057 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
8058 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
8060 LeaveCriticalSection( &freetype_cs
);
8064 /*************************************************************
8065 * freetype_GetCharABCWidthsI
8067 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
8069 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8072 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8076 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
8077 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
8080 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
8084 EnterCriticalSection( &freetype_cs
);
8086 for(c
= 0; c
< count
; c
++, buffer
++)
8087 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
8088 &gm
, buffer
, 0, NULL
, &identity
);
8090 LeaveCriticalSection( &freetype_cs
);
8094 /*************************************************************
8095 * freetype_GetTextExtentExPoint
8097 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
8099 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8103 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8107 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
8108 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
8111 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
8114 EnterCriticalSection( &freetype_cs
);
8116 for (idx
= pos
= 0; idx
< count
; idx
++)
8118 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
8119 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8123 LeaveCriticalSection( &freetype_cs
);
8127 /*************************************************************
8128 * freetype_GetTextExtentExPointI
8130 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
8132 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8136 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8140 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
8141 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
8144 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
8147 EnterCriticalSection( &freetype_cs
);
8149 for (idx
= pos
= 0; idx
< count
; idx
++)
8151 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
8152 &gm
, &abc
, 0, NULL
, &identity
);
8153 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8157 LeaveCriticalSection( &freetype_cs
);
8161 /*************************************************************
8162 * freetype_GetFontData
8164 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
8166 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8170 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
8171 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
8174 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
8175 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
8176 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
8178 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
8181 /*************************************************************
8182 * freetype_GetTextFace
8184 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
8187 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8191 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
8192 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
8195 n
= strlenW(physdev
->font
->name
) + 1;
8198 lstrcpynW(str
, physdev
->font
->name
, count
);
8204 /*************************************************************
8205 * freetype_GetTextCharsetInfo
8207 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
8209 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8213 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
8214 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
8216 if (fs
) *fs
= physdev
->font
->fs
;
8217 return physdev
->font
->charset
;
8220 /* Retrieve a list of supported Unicode ranges for a given font.
8221 * Can be called with NULL gs to calculate the buffer size. Returns
8222 * the number of ranges found.
8224 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
8226 DWORD num_ranges
= 0;
8228 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8231 FT_ULong char_code
, char_code_prev
;
8234 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
8236 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8237 face
->num_glyphs
, glyph_code
, char_code
);
8239 if (!glyph_code
) return 0;
8243 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
8244 gs
->ranges
[0].cGlyphs
= 0;
8245 gs
->cGlyphsSupported
= 0;
8251 if (char_code
< char_code_prev
)
8253 ERR("expected increasing char code from FT_Get_Next_Char\n");
8256 if (char_code
- char_code_prev
> 1)
8261 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
8262 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
8263 gs
->cGlyphsSupported
++;
8268 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
8269 gs
->cGlyphsSupported
++;
8271 char_code_prev
= char_code
;
8272 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
8276 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
8281 /*************************************************************
8282 * freetype_GetFontUnicodeRanges
8284 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
8286 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8287 DWORD size
, num_ranges
;
8291 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
8292 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
8295 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
8296 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
8299 glyphset
->cbThis
= size
;
8300 glyphset
->cRanges
= num_ranges
;
8301 glyphset
->flAccel
= 0;
8306 /*************************************************************
8307 * freetype_FontIsLinked
8309 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
8311 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8316 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
8317 return dev
->funcs
->pFontIsLinked( dev
);
8321 EnterCriticalSection( &freetype_cs
);
8322 ret
= !list_empty(&physdev
->font
->child_fonts
);
8323 LeaveCriticalSection( &freetype_cs
);
8327 /*************************************************************************
8328 * GetRasterizerCaps (GDI32.@)
8330 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8332 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8333 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
8334 lprs
->nLanguageID
= 0;
8338 /*************************************************************
8339 * freetype_GetFontRealizationInfo
8341 static BOOL
freetype_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
8343 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8344 struct font_realization_info
*info
= ptr
;
8348 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
8349 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
8352 TRACE("(%p, %p)\n", physdev
->font
, info
);
8355 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8358 info
->cache_num
= physdev
->font
->cache_num
;
8359 info
->instance_id
= physdev
->font
->instance_id
;
8360 if (info
->size
== sizeof(*info
))
8363 info
->face_index
= physdev
->font
->ft_face
->face_index
;
8364 info
->simulations
= 0;
8365 if (physdev
->font
->fake_bold
)
8366 info
->simulations
|= 0x1;
8367 if (physdev
->font
->fake_italic
)
8368 info
->simulations
|= 0x2;
8374 /*************************************************************************
8375 * GetFontFileInfo (GDI32.@)
8377 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
, DWORD size
, DWORD
*needed
)
8379 struct font_handle_entry
*entry
= handle_entry( instance_id
);
8380 const GdiFont
*font
;
8384 SetLastError(ERROR_INVALID_PARAMETER
);
8389 *needed
= sizeof(*info
) + strlenW(font
->fileinfo
->path
) * sizeof(WCHAR
);
8392 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
8396 /* path is included too */
8397 memcpy(info
, font
->fileinfo
, *needed
);
8401 /*************************************************************************
8402 * Kerning support for TrueType fonts
8404 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8406 struct TT_kern_table
8412 struct TT_kern_subtable
8421 USHORT horizontal
: 1;
8423 USHORT cross_stream
: 1;
8424 USHORT override
: 1;
8425 USHORT reserved1
: 4;
8431 struct TT_format0_kern_subtable
8435 USHORT entrySelector
;
8446 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8447 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8448 const USHORT
*glyph_to_char
,
8449 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8452 const struct TT_kern_pair
*tt_kern_pair
;
8454 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8456 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8458 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8459 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8460 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8462 if (!kern_pair
|| !cPairs
)
8465 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8467 nPairs
= min(nPairs
, cPairs
);
8469 for (i
= 0; i
< nPairs
; i
++)
8471 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8472 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8473 /* this algorithm appears to better match what Windows does */
8474 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8475 if (kern_pair
->iKernAmount
< 0)
8477 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8478 kern_pair
->iKernAmount
-= font
->ppem
;
8480 else if (kern_pair
->iKernAmount
> 0)
8482 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8483 kern_pair
->iKernAmount
+= font
->ppem
;
8485 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8487 TRACE("left %u right %u value %d\n",
8488 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8492 TRACE("copied %u entries\n", nPairs
);
8496 /*************************************************************
8497 * freetype_GetKerningPairs
8499 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8503 const struct TT_kern_table
*tt_kern_table
;
8504 const struct TT_kern_subtable
*tt_kern_subtable
;
8506 USHORT
*glyph_to_char
;
8508 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8510 if (!(font
= physdev
->font
))
8512 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8513 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8517 EnterCriticalSection( &freetype_cs
);
8518 if (font
->total_kern_pairs
!= (DWORD
)-1)
8520 if (cPairs
&& kern_pair
)
8522 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8523 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8525 else cPairs
= font
->total_kern_pairs
;
8527 LeaveCriticalSection( &freetype_cs
);
8531 font
->total_kern_pairs
= 0;
8533 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8535 if (length
== GDI_ERROR
)
8537 TRACE("no kerning data in the font\n");
8538 LeaveCriticalSection( &freetype_cs
);
8542 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8545 WARN("Out of memory\n");
8546 LeaveCriticalSection( &freetype_cs
);
8550 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8552 /* build a glyph index to char code map */
8553 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8556 WARN("Out of memory allocating a glyph index to char code map\n");
8557 HeapFree(GetProcessHeap(), 0, buf
);
8558 LeaveCriticalSection( &freetype_cs
);
8562 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8568 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8570 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8571 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8575 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8577 /* FIXME: This doesn't match what Windows does: it does some fancy
8578 * things with duplicate glyph index to char code mappings, while
8579 * we just avoid overriding existing entries.
8581 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8582 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8584 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8591 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8592 for (n
= 0; n
<= 65535; n
++)
8593 glyph_to_char
[n
] = (USHORT
)n
;
8596 tt_kern_table
= buf
;
8597 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8598 TRACE("version %u, nTables %u\n",
8599 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8601 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8603 for (i
= 0; i
< nTables
; i
++)
8605 struct TT_kern_subtable tt_kern_subtable_copy
;
8607 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8608 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8609 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8611 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8612 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8613 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8615 /* According to the TrueType specification this is the only format
8616 * that will be properly interpreted by Windows and OS/2
8618 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8620 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8622 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8623 glyph_to_char
, NULL
, 0);
8624 font
->total_kern_pairs
+= new_chunk
;
8626 if (!font
->kern_pairs
)
8627 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8628 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8630 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8631 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8633 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8634 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8637 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8639 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8642 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8643 HeapFree(GetProcessHeap(), 0, buf
);
8645 if (cPairs
&& kern_pair
)
8647 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8648 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8650 else cPairs
= font
->total_kern_pairs
;
8652 LeaveCriticalSection( &freetype_cs
);
8656 static const struct gdi_dc_funcs freetype_funcs
=
8658 NULL
, /* pAbortDoc */
8659 NULL
, /* pAbortPath */
8660 NULL
, /* pAlphaBlend */
8661 NULL
, /* pAngleArc */
8664 NULL
, /* pBeginPath */
8665 NULL
, /* pBlendImage */
8667 NULL
, /* pCloseFigure */
8668 NULL
, /* pCreateCompatibleDC */
8669 freetype_CreateDC
, /* pCreateDC */
8670 freetype_DeleteDC
, /* pDeleteDC */
8671 NULL
, /* pDeleteObject */
8672 NULL
, /* pDeviceCapabilities */
8673 NULL
, /* pEllipse */
8675 NULL
, /* pEndPage */
8676 NULL
, /* pEndPath */
8677 freetype_EnumFonts
, /* pEnumFonts */
8678 NULL
, /* pEnumICMProfiles */
8679 NULL
, /* pExcludeClipRect */
8680 NULL
, /* pExtDeviceMode */
8681 NULL
, /* pExtEscape */
8682 NULL
, /* pExtFloodFill */
8683 NULL
, /* pExtSelectClipRgn */
8684 NULL
, /* pExtTextOut */
8685 NULL
, /* pFillPath */
8686 NULL
, /* pFillRgn */
8687 NULL
, /* pFlattenPath */
8688 freetype_FontIsLinked
, /* pFontIsLinked */
8689 NULL
, /* pFrameRgn */
8690 NULL
, /* pGdiComment */
8691 NULL
, /* pGetBoundsRect */
8692 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8693 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8694 freetype_GetCharWidth
, /* pGetCharWidth */
8695 NULL
, /* pGetDeviceCaps */
8696 NULL
, /* pGetDeviceGammaRamp */
8697 freetype_GetFontData
, /* pGetFontData */
8698 freetype_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
8699 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8700 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8701 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8702 NULL
, /* pGetICMProfile */
8703 NULL
, /* pGetImage */
8704 freetype_GetKerningPairs
, /* pGetKerningPairs */
8705 NULL
, /* pGetNearestColor */
8706 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8707 NULL
, /* pGetPixel */
8708 NULL
, /* pGetSystemPaletteEntries */
8709 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8710 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8711 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8712 freetype_GetTextFace
, /* pGetTextFace */
8713 freetype_GetTextMetrics
, /* pGetTextMetrics */
8714 NULL
, /* pGradientFill */
8715 NULL
, /* pIntersectClipRect */
8716 NULL
, /* pInvertRgn */
8718 NULL
, /* pModifyWorldTransform */
8720 NULL
, /* pOffsetClipRgn */
8721 NULL
, /* pOffsetViewportOrg */
8722 NULL
, /* pOffsetWindowOrg */
8723 NULL
, /* pPaintRgn */
8726 NULL
, /* pPolyBezier */
8727 NULL
, /* pPolyBezierTo */
8728 NULL
, /* pPolyDraw */
8729 NULL
, /* pPolyPolygon */
8730 NULL
, /* pPolyPolyline */
8731 NULL
, /* pPolygon */
8732 NULL
, /* pPolyline */
8733 NULL
, /* pPolylineTo */
8734 NULL
, /* pPutImage */
8735 NULL
, /* pRealizeDefaultPalette */
8736 NULL
, /* pRealizePalette */
8737 NULL
, /* pRectangle */
8738 NULL
, /* pResetDC */
8739 NULL
, /* pRestoreDC */
8740 NULL
, /* pRoundRect */
8742 NULL
, /* pScaleViewportExt */
8743 NULL
, /* pScaleWindowExt */
8744 NULL
, /* pSelectBitmap */
8745 NULL
, /* pSelectBrush */
8746 NULL
, /* pSelectClipPath */
8747 freetype_SelectFont
, /* pSelectFont */
8748 NULL
, /* pSelectPalette */
8749 NULL
, /* pSelectPen */
8750 NULL
, /* pSetArcDirection */
8751 NULL
, /* pSetBkColor */
8752 NULL
, /* pSetBkMode */
8753 NULL
, /* pSetDCBrushColor */
8754 NULL
, /* pSetDCPenColor */
8755 NULL
, /* pSetDIBColorTable */
8756 NULL
, /* pSetDIBitsToDevice */
8757 NULL
, /* pSetDeviceClipping */
8758 NULL
, /* pSetDeviceGammaRamp */
8759 NULL
, /* pSetLayout */
8760 NULL
, /* pSetMapMode */
8761 NULL
, /* pSetMapperFlags */
8762 NULL
, /* pSetPixel */
8763 NULL
, /* pSetPolyFillMode */
8764 NULL
, /* pSetROP2 */
8765 NULL
, /* pSetRelAbs */
8766 NULL
, /* pSetStretchBltMode */
8767 NULL
, /* pSetTextAlign */
8768 NULL
, /* pSetTextCharacterExtra */
8769 NULL
, /* pSetTextColor */
8770 NULL
, /* pSetTextJustification */
8771 NULL
, /* pSetViewportExt */
8772 NULL
, /* pSetViewportOrg */
8773 NULL
, /* pSetWindowExt */
8774 NULL
, /* pSetWindowOrg */
8775 NULL
, /* pSetWorldTransform */
8776 NULL
, /* pStartDoc */
8777 NULL
, /* pStartPage */
8778 NULL
, /* pStretchBlt */
8779 NULL
, /* pStretchDIBits */
8780 NULL
, /* pStrokeAndFillPath */
8781 NULL
, /* pStrokePath */
8782 NULL
, /* pUnrealizePalette */
8783 NULL
, /* pWidenPath */
8784 NULL
, /* wine_get_wgl_driver */
8785 GDI_PRIORITY_FONT_DRV
/* priority */
8788 #else /* HAVE_FREETYPE */
8790 struct font_fileinfo
;
8792 /*************************************************************************/
8794 BOOL
WineEngInit(void)
8799 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8801 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8805 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8807 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8811 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8813 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8817 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8818 LPCWSTR font_file
, LPCWSTR font_path
)
8824 /*************************************************************************
8825 * GetRasterizerCaps (GDI32.@)
8827 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8829 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8831 lprs
->nLanguageID
= 0;
8835 /*************************************************************************
8836 * GetFontFileInfo (GDI32.@)
8838 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
, DWORD size
, DWORD
*needed
)
8844 #endif /* HAVE_FREETYPE */