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_Length
);
166 MAKE_FUNCPTR(FT_Vector_Transform
);
167 MAKE_FUNCPTR(FT_Vector_Unit
);
168 static FT_Error (*pFT_Outline_Embolden
)(FT_Outline
*, FT_Pos
);
169 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
170 #ifdef FT_LCD_FILTER_H
171 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
174 #ifdef SONAME_LIBFONTCONFIG
175 #include <fontconfig/fontconfig.h>
176 MAKE_FUNCPTR(FcConfigSubstitute
);
177 MAKE_FUNCPTR(FcFontList
);
178 MAKE_FUNCPTR(FcFontSetDestroy
);
179 MAKE_FUNCPTR(FcInit
);
180 MAKE_FUNCPTR(FcObjectSetAdd
);
181 MAKE_FUNCPTR(FcObjectSetCreate
);
182 MAKE_FUNCPTR(FcObjectSetDestroy
);
183 MAKE_FUNCPTR(FcPatternCreate
);
184 MAKE_FUNCPTR(FcPatternDestroy
);
185 MAKE_FUNCPTR(FcPatternGetBool
);
186 MAKE_FUNCPTR(FcPatternGetInteger
);
187 MAKE_FUNCPTR(FcPatternGetString
);
193 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
194 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
195 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
198 #ifndef ft_encoding_none
199 #define FT_ENCODING_NONE ft_encoding_none
201 #ifndef ft_encoding_ms_symbol
202 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
204 #ifndef ft_encoding_unicode
205 #define FT_ENCODING_UNICODE ft_encoding_unicode
207 #ifndef ft_encoding_apple_roman
208 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
211 #ifdef WORDS_BIGENDIAN
212 #define GET_BE_WORD(x) (x)
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
217 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
224 FT_Short internal_leading
;
227 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
228 So to let this compile on older versions of FreeType we'll define the
229 new structure here. */
231 FT_Short height
, width
;
232 FT_Pos size
, x_ppem
, y_ppem
;
238 NEWTEXTMETRICEXW ntm
;
242 typedef struct tagFace
{
244 unsigned int refcount
;
251 DWORD font_data_size
;
255 FT_Fixed font_version
;
257 Bitmap_Size size
; /* set if face is a bitmap */
258 DWORD flags
; /* ADDFONT flags */
259 struct tagFamily
*family
;
260 /* Cached data for Enum */
261 struct enum_data
*cached_enum_data
;
264 #define ADDFONT_EXTERNAL_FONT 0x01
265 #define ADDFONT_ALLOW_BITMAP 0x02
266 #define ADDFONT_ADD_TO_CACHE 0x04
267 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
268 #define ADDFONT_VERTICAL_FONT 0x10
269 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
271 typedef struct tagFamily
{
273 unsigned int refcount
;
277 struct list
*replacement
;
282 ABC abc
; /* metrics of the unrotated char */
298 typedef struct tagGdiFont GdiFont
;
300 #define FIRST_FONT_HANDLE 1
301 #define MAX_FONT_HANDLES 256
303 struct font_handle_entry
306 WORD generation
; /* generation count for reusing handle values */
309 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
310 static struct font_handle_entry
*next_free
;
311 static struct font_handle_entry
*next_unused
= font_handles
;
313 static inline DWORD
entry_to_handle( struct font_handle_entry
*entry
)
315 unsigned int idx
= entry
- font_handles
+ FIRST_FONT_HANDLE
;
316 return idx
| (entry
->generation
<< 16);
319 static inline struct font_handle_entry
*handle_entry( DWORD handle
)
321 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
323 if (idx
< MAX_FONT_HANDLES
)
325 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
326 return &font_handles
[idx
];
328 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
332 static DWORD
alloc_font_handle( void *obj
)
334 struct font_handle_entry
*entry
;
338 next_free
= entry
->obj
;
339 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
340 entry
= next_unused
++;
343 ERR( "out of realized font handles\n" );
347 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
348 return entry_to_handle( entry
);
351 static void free_font_handle( DWORD handle
)
353 struct font_handle_entry
*entry
;
355 if ((entry
= handle_entry( handle
)))
357 entry
->obj
= next_free
;
368 struct font_fileinfo
{
376 struct list unused_entry
;
377 unsigned int refcount
;
380 OUTLINETEXTMETRICW
*potm
;
381 DWORD total_kern_pairs
;
382 KERNINGPAIR
*kern_pairs
;
383 struct list child_fonts
;
385 /* the following members can be accessed without locking, they are never modified after creation */
387 struct font_mapping
*mapping
;
403 UINT ntmCellHeight
, ntmAvgWidth
;
407 const VOID
*vert_feature
;
410 struct font_fileinfo
*fileinfo
;
415 const WCHAR
*font_name
;
420 struct enum_charset_element
{
423 WCHAR name
[LF_FACESIZE
];
426 struct enum_charset_list
{
428 struct enum_charset_element element
[32];
431 #define GM_BLOCK_SIZE 128
432 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
434 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
435 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
436 static unsigned int unused_font_count
;
437 #define UNUSED_CACHE_SIZE 10
438 static struct list system_links
= LIST_INIT(system_links
);
440 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
442 static struct list font_list
= LIST_INIT(font_list
);
444 struct freetype_physdev
446 struct gdi_physdev dev
;
450 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
452 return (struct freetype_physdev
*)dev
;
455 static const struct gdi_dc_funcs freetype_funcs
;
457 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
458 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
459 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
461 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
462 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
463 'W','i','n','d','o','w','s','\\',
464 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
465 'F','o','n','t','s','\0'};
467 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
468 'W','i','n','d','o','w','s',' ','N','T','\\',
469 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
470 'F','o','n','t','s','\0'};
472 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
473 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
474 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
475 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
477 static const WCHAR
* const SystemFontValues
[] = {
484 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
485 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
487 /* Interesting and well-known (frequently-assumed!) font names */
488 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
489 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 };
490 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
491 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
492 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
493 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
494 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
495 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
497 static const WCHAR arial
[] = {'A','r','i','a','l',0};
498 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
499 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};
500 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};
501 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
502 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
503 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
504 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
505 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
506 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
508 static const WCHAR
*default_serif_list
[] =
512 bitstream_vera_serif
,
516 static const WCHAR
*default_fixed_list
[] =
520 bitstream_vera_sans_mono
,
524 static const WCHAR
*default_sans_list
[] =
537 typedef struct tagFontSubst
{
543 /* Registry font cache key and value names */
544 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
545 'F','o','n','t','s',0};
546 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
547 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
548 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
549 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
550 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
551 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
552 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
553 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
554 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
555 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
556 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
557 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
558 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
559 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
560 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
573 static struct list mappings_list
= LIST_INIT( mappings_list
);
575 static UINT default_aa_flags
;
576 static HKEY hkey_font_cache
;
577 static BOOL antialias_fakes
= TRUE
;
579 static CRITICAL_SECTION freetype_cs
;
580 static CRITICAL_SECTION_DEBUG critsect_debug
=
583 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
584 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
586 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
588 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
590 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
591 static BOOL use_default_fallback
= FALSE
;
593 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
*vert
);
594 static BOOL
get_outline_text_metrics(GdiFont
*font
);
595 static BOOL
get_bitmap_text_metrics(GdiFont
*font
);
596 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
597 static void remove_face_from_cache( Face
*face
);
599 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
600 'W','i','n','d','o','w','s',' ','N','T','\\',
601 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
602 'S','y','s','t','e','m','L','i','n','k',0};
604 /****************************************
605 * Notes on .fon files
607 * The fonts System, FixedSys and Terminal are special. There are typically multiple
608 * versions installed for different resolutions and codepages. Windows stores which one to use
609 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
611 * FIXEDFON.FON FixedSys
613 * OEMFONT.FON Terminal
614 * LogPixels Current dpi set by the display control panel applet
615 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
616 * also has a LogPixels value that appears to mirror this)
618 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
619 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
620 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
621 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
622 * so that makes sense.
624 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
625 * to be mapped into the registry on Windows 2000 at least).
628 * ega80woa.fon=ega80850.fon
629 * ega40woa.fon=ega40850.fon
630 * cga80woa.fon=cga80850.fon
631 * cga40woa.fon=cga40850.fon
634 /* These are all structures needed for the GSUB table */
636 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
652 GSUB_ScriptRecord ScriptRecord
[1];
658 } GSUB_LangSysRecord
;
663 GSUB_LangSysRecord LangSysRecord
[1];
667 WORD LookupOrder
; /* Reserved */
668 WORD ReqFeatureIndex
;
670 WORD FeatureIndex
[1];
676 } GSUB_FeatureRecord
;
680 GSUB_FeatureRecord FeatureRecord
[1];
684 WORD FeatureParams
; /* Reserved */
686 WORD LookupListIndex
[1];
705 } GSUB_CoverageFormat1
;
710 WORD StartCoverageIndex
;
716 GSUB_RangeRecord RangeRecord
[1];
717 } GSUB_CoverageFormat2
;
720 WORD SubstFormat
; /* = 1 */
723 } GSUB_SingleSubstFormat1
;
726 WORD SubstFormat
; /* = 2 */
730 }GSUB_SingleSubstFormat2
;
732 #ifdef HAVE_CARBON_CARBON_H
733 static char *find_cache_dir(void)
737 static char cached_path
[MAX_PATH
];
738 static const char *wine
= "/Wine", *fonts
= "/Fonts";
740 if(*cached_path
) return cached_path
;
742 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
745 WARN("can't create cached data folder\n");
748 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
751 WARN("can't create cached data path\n");
755 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
757 ERR("Could not create full path\n");
761 strcat(cached_path
, wine
);
763 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
765 WARN("Couldn't mkdir %s\n", cached_path
);
769 strcat(cached_path
, fonts
);
770 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
772 WARN("Couldn't mkdir %s\n", cached_path
);
779 /******************************************************************
782 * Extracts individual TrueType font files from a Mac suitcase font
783 * and saves them into the user's caches directory (see
785 * Returns a NULL terminated array of filenames.
787 * We do this because they are apps that try to read ttf files
788 * themselves and they don't like Mac suitcase files.
790 static char **expand_mac_font(const char *path
)
797 const char *filename
;
801 unsigned int size
, max_size
;
804 TRACE("path %s\n", path
);
806 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
809 WARN("failed to get ref\n");
813 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
816 TRACE("no data fork, so trying resource fork\n");
817 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
820 TRACE("unable to open resource fork\n");
827 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
830 CloseResFile(res_ref
);
834 out_dir
= find_cache_dir();
836 filename
= strrchr(path
, '/');
837 if(!filename
) filename
= path
;
840 /* output filename has the form out_dir/filename_%04x.ttf */
841 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
848 unsigned short *num_faces_ptr
, num_faces
, face
;
851 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
853 fond
= Get1IndResource(fond_res
, idx
);
855 TRACE("got fond resource %d\n", idx
);
858 fam_rec
= *(FamRec
**)fond
;
859 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
860 num_faces
= GET_BE_WORD(*num_faces_ptr
);
862 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
863 TRACE("num faces %04x\n", num_faces
);
864 for(face
= 0; face
< num_faces
; face
++, assoc
++)
867 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
868 unsigned short size
, font_id
;
871 size
= GET_BE_WORD(assoc
->fontSize
);
872 font_id
= GET_BE_WORD(assoc
->fontID
);
875 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
879 TRACE("trying to load sfnt id %04x\n", font_id
);
880 sfnt
= GetResource(sfnt_res
, font_id
);
883 TRACE("can't get sfnt resource %04x\n", font_id
);
887 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
892 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
894 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
895 if(fd
!= -1 || errno
== EEXIST
)
899 unsigned char *sfnt_data
;
902 sfnt_data
= *(unsigned char**)sfnt
;
903 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
907 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
910 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
912 ret
.array
[ret
.size
++] = output
;
916 WARN("unable to create %s\n", output
);
917 HeapFree(GetProcessHeap(), 0, output
);
920 ReleaseResource(sfnt
);
923 ReleaseResource(fond
);
926 CloseResFile(res_ref
);
931 #endif /* HAVE_CARBON_CARBON_H */
933 static inline BOOL
is_win9x(void)
935 return GetVersion() & 0x80000000;
938 This function builds an FT_Fixed from a double. It fails if the absolute
939 value of the float number is greater than 32768.
941 static inline FT_Fixed
FT_FixedFromFloat(double f
)
947 This function builds an FT_Fixed from a FIXED. It simply put f.value
948 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
950 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
952 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
955 static BOOL
is_hinting_enabled(void)
957 static int enabled
= -1;
961 /* Use the >= 2.2.0 function if available */
962 if (pFT_Get_TrueType_Engine_Type
)
964 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
965 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
967 else enabled
= FALSE
;
968 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
973 static BOOL
is_subpixel_rendering_enabled( void )
975 #ifdef FT_LCD_FILTER_H
976 static int enabled
= -1;
979 enabled
= (pFT_Library_SetLcdFilter
&&
980 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
981 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
990 static const struct list
*get_face_list_from_family(const Family
*family
)
992 if (!list_empty(&family
->faces
))
993 return &family
->faces
;
995 return family
->replacement
;
998 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
1004 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
1006 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1008 const struct list
*face_list
;
1009 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
1011 face_list
= get_face_list_from_family(family
);
1012 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
1016 file
= strrchrW(face
->file
, '/');
1021 if(strcmpiW(file
, file_name
)) continue;
1029 static Family
*find_family_from_name(const WCHAR
*name
)
1033 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1035 if(!strcmpiW(family
->FamilyName
, name
))
1042 static Family
*find_family_from_any_name(const WCHAR
*name
)
1046 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1048 if(!strcmpiW(family
->FamilyName
, name
))
1050 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1057 static void DumpSubstList(void)
1061 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1063 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1064 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1065 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1067 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1068 debugstr_w(psub
->to
.name
));
1072 static LPWSTR
strdupW(LPCWSTR p
)
1075 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1076 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1077 memcpy(ret
, p
, len
);
1081 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1086 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1088 if(!strcmpiW(element
->from
.name
, from_name
) &&
1089 (element
->from
.charset
== from_charset
||
1090 element
->from
.charset
== -1))
1097 #define ADD_FONT_SUBST_FORCE 1
1099 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1101 FontSubst
*from_exist
, *to_exist
;
1103 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1105 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1107 list_remove(&from_exist
->entry
);
1108 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1109 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1110 HeapFree(GetProcessHeap(), 0, from_exist
);
1116 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1120 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1121 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1124 list_add_tail(subst_list
, &subst
->entry
);
1129 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1130 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1131 HeapFree(GetProcessHeap(), 0, subst
);
1135 static WCHAR
*towstr(UINT cp
, const char *str
)
1140 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1141 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1142 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1146 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1148 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1149 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1150 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1154 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1156 CHAR
*p
= strrchr(str
, ',');
1160 nc
->charset
= strtol(p
+1, NULL
, 10);
1163 nc
->name
= towstr(CP_ACP
, str
);
1166 static void LoadSubstList(void)
1170 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1174 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1175 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1176 &hkey
) == ERROR_SUCCESS
) {
1178 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1179 &valuelen
, &datalen
, NULL
, NULL
);
1181 valuelen
++; /* returned value doesn't include room for '\0' */
1182 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1183 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1187 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1188 &dlen
) == ERROR_SUCCESS
) {
1189 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1191 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1192 split_subst_info(&psub
->from
, value
);
1193 split_subst_info(&psub
->to
, data
);
1195 /* Win 2000 doesn't allow mapping between different charsets
1196 or mapping of DEFAULT_CHARSET */
1197 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1198 psub
->to
.charset
== DEFAULT_CHARSET
) {
1199 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1200 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1201 HeapFree(GetProcessHeap(), 0, psub
);
1203 add_font_subst(&font_subst_list
, psub
, 0);
1205 /* reset dlen and vlen */
1209 HeapFree(GetProcessHeap(), 0, data
);
1210 HeapFree(GetProcessHeap(), 0, value
);
1216 static const LANGID mac_langid_table
[] =
1218 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
1219 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
1220 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
1221 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
1222 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
1223 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
1224 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
1225 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
1226 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
1227 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
1228 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
1229 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
1230 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
1231 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
1232 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
1233 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
1234 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
1235 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
1236 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
1237 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1238 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
1239 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
1240 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
1241 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
1242 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
1243 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
1244 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
1245 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
1246 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
1247 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
1248 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
1249 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
1250 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
1251 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1252 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
1253 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
1254 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
1255 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
1256 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
1257 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
1258 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
1259 0, /* TT_MAC_LANGID_YIDDISH */
1260 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
1261 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
1262 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
1263 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
1264 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
1265 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
1266 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
1267 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
1268 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1269 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
1270 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
1271 0, /* TT_MAC_LANGID_MOLDAVIAN */
1272 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
1273 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
1274 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
1275 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
1276 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1277 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
1278 0, /* TT_MAC_LANGID_KURDISH */
1279 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
1280 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
1281 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
1282 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
1283 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
1284 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
1285 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
1286 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
1287 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
1288 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
1289 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
1290 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
1291 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
1292 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
1293 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
1294 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
1295 0, /* TT_MAC_LANGID_BURMESE */
1296 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
1297 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
1298 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
1299 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
1300 0, /* TT_MAC_LANGID_TAGALOG */
1301 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1302 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1303 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
1304 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
1305 0, /* TT_MAC_LANGID_GALLA */
1306 0, /* TT_MAC_LANGID_SOMALI */
1307 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
1308 0, /* TT_MAC_LANGID_RUANDA */
1309 0, /* TT_MAC_LANGID_RUNDI */
1310 0, /* TT_MAC_LANGID_CHEWA */
1311 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
1312 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
1313 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1314 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1315 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
1316 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
1317 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
1318 0, /* TT_MAC_LANGID_LATIN */
1319 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
1320 0, /* TT_MAC_LANGID_GUARANI */
1321 0, /* TT_MAC_LANGID_AYMARA */
1322 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
1323 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
1324 0, /* TT_MAC_LANGID_DZONGKHA */
1325 0, /* TT_MAC_LANGID_JAVANESE */
1326 0, /* TT_MAC_LANGID_SUNDANESE */
1327 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
1328 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
1329 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
1330 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
1331 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1332 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
1333 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
1334 0, /* TT_MAC_LANGID_TONGAN */
1335 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1336 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
1337 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1340 static inline WORD
get_mac_code_page( const FT_SfntName
*name
)
1342 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
1343 return 10000 + name
->encoding_id
;
1346 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
1351 switch (name
->platform_id
)
1353 case TT_PLATFORM_MICROSOFT
:
1354 res
+= 5; /* prefer the Microsoft name */
1355 switch (name
->encoding_id
)
1357 case TT_MS_ID_UNICODE_CS
:
1358 case TT_MS_ID_SYMBOL_CS
:
1359 name_lang
= name
->language_id
;
1365 case TT_PLATFORM_MACINTOSH
:
1366 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
1367 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1368 name_lang
= mac_langid_table
[name
->language_id
];
1370 case TT_PLATFORM_APPLE_UNICODE
:
1371 res
+= 2; /* prefer Unicode encodings */
1372 switch (name
->encoding_id
)
1374 case TT_APPLE_ID_DEFAULT
:
1375 case TT_APPLE_ID_ISO_10646
:
1376 case TT_APPLE_ID_UNICODE_2_0
:
1377 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1378 name_lang
= mac_langid_table
[name
->language_id
];
1387 if (name_lang
== lang
) res
+= 30;
1388 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
1389 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
1393 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
1399 switch (name
->platform_id
)
1401 case TT_PLATFORM_APPLE_UNICODE
:
1402 case TT_PLATFORM_MICROSOFT
:
1403 ret
= HeapAlloc( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
1404 for (i
= 0; i
< name
->string_len
/ 2; i
++)
1405 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
1408 case TT_PLATFORM_MACINTOSH
:
1409 codepage
= get_mac_code_page( name
);
1410 i
= MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, NULL
, 0 );
1411 ret
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(WCHAR
) );
1412 MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, ret
, i
);
1419 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
1422 FT_UInt num_names
, name_index
;
1423 int res
, best_lang
= 0, best_index
= -1;
1425 if (!FT_IS_SFNT(ft_face
)) return NULL
;
1427 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
1429 for (name_index
= 0; name_index
< num_names
; name_index
++)
1431 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
1432 if (name
.name_id
!= name_id
) continue;
1433 res
= match_name_table_language( &name
, language_id
);
1434 if (res
> best_lang
)
1437 best_index
= name_index
;
1441 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
1443 WCHAR
*ret
= copy_name_table_string( &name
);
1444 TRACE( "name %u found platform %u lang %04x %s\n",
1445 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
1451 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1453 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1454 if (f1
->scalable
) return TRUE
;
1455 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1456 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1459 static void release_family( Family
*family
)
1461 if (--family
->refcount
) return;
1462 assert( list_empty( &family
->faces
));
1463 list_remove( &family
->entry
);
1464 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1465 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1466 HeapFree( GetProcessHeap(), 0, family
);
1469 static void release_face( Face
*face
)
1471 if (--face
->refcount
) return;
1474 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1475 list_remove( &face
->entry
);
1476 release_family( face
->family
);
1478 HeapFree( GetProcessHeap(), 0, face
->file
);
1479 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1480 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1481 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1482 HeapFree( GetProcessHeap(), 0, face
);
1485 static inline int style_order(const Face
*face
)
1487 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1495 case NTM_BOLD
| NTM_ITALIC
:
1498 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1499 debugstr_w(face
->family
->FamilyName
),
1500 debugstr_w(face
->StyleName
),
1506 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1510 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1512 if (faces_equal( face
, cursor
))
1514 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1515 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1516 cursor
->font_version
, face
->font_version
);
1518 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1521 TRACE("Font %s already in list, refcount now %d\n",
1522 debugstr_w(face
->file
), cursor
->refcount
);
1525 if (face
->font_version
<= cursor
->font_version
)
1527 TRACE("Original font %s is newer so skipping %s\n",
1528 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1533 TRACE("Replacing original %s with %s\n",
1534 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1535 list_add_before( &cursor
->entry
, &face
->entry
);
1536 face
->family
= family
;
1539 release_face( cursor
);
1544 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1546 if (style_order( face
) < style_order( cursor
)) break;
1549 list_add_before( &cursor
->entry
, &face
->entry
);
1550 face
->family
= family
;
1556 /****************************************************************
1557 * NB This function stores the ptrs to the strings to save copying.
1558 * Don't free them after calling.
1560 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1562 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1563 family
->refcount
= 1;
1564 family
->FamilyName
= name
;
1565 family
->EnglishName
= english_name
;
1566 list_init( &family
->faces
);
1567 family
->replacement
= &family
->faces
;
1568 list_add_tail( &font_list
, &family
->entry
);
1573 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1575 DWORD type
, size
= sizeof(DWORD
);
1577 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1578 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1581 return ERROR_BAD_CONFIGURATION
;
1583 return ERROR_SUCCESS
;
1586 static inline LONG
reg_load_ftlong(HKEY hkey
, const WCHAR
*value
, FT_Long
*data
)
1589 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1594 static inline LONG
reg_load_ftshort(HKEY hkey
, const WCHAR
*value
, FT_Short
*data
)
1597 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1602 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1604 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1607 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1609 DWORD needed
, strike_index
= 0;
1612 /* If we have a File Name key then this is a real font, not just the parent
1613 key of a bunch of non-scalable strikes */
1614 needed
= buffer_size
;
1615 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1618 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1619 face
->cached_enum_data
= NULL
;
1620 face
->family
= NULL
;
1623 face
->file
= strdupW( buffer
);
1624 face
->StyleName
= strdupW(face_name
);
1626 needed
= buffer_size
;
1627 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1628 face
->FullName
= strdupW( buffer
);
1630 face
->FullName
= NULL
;
1632 reg_load_ftlong(hkey_face
, face_index_value
, &face
->face_index
);
1633 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1634 reg_load_ftlong(hkey_face
, face_version_value
, &face
->font_version
);
1635 reg_load_dword(hkey_face
, face_flags_value
, &face
->flags
);
1637 needed
= sizeof(face
->fs
);
1638 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1640 if(reg_load_ftshort(hkey_face
, face_height_value
, &face
->size
.height
) != ERROR_SUCCESS
)
1642 face
->scalable
= TRUE
;
1643 memset(&face
->size
, 0, sizeof(face
->size
));
1647 face
->scalable
= FALSE
;
1648 reg_load_ftshort(hkey_face
, face_width_value
, &face
->size
.width
);
1649 reg_load_ftlong(hkey_face
, face_size_value
, &face
->size
.size
);
1650 reg_load_ftlong(hkey_face
, face_x_ppem_value
, &face
->size
.x_ppem
);
1651 reg_load_ftlong(hkey_face
, face_y_ppem_value
, &face
->size
.y_ppem
);
1652 reg_load_ftshort(hkey_face
, face_internal_leading_value
, &face
->size
.internal_leading
);
1654 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1655 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1656 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1659 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1660 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1661 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1662 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1664 if (insert_face_in_family_list(face
, family
))
1665 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1667 release_face( face
);
1670 /* load bitmap strikes */
1672 needed
= buffer_size
;
1673 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1675 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1677 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1678 RegCloseKey(hkey_strike
);
1680 needed
= buffer_size
;
1684 /* move vertical fonts after their horizontal counterpart */
1685 /* assumes that font_list is already sorted by family name */
1686 static void reorder_vertical_fonts(void)
1688 Family
*family
, *next
, *vert_family
;
1689 struct list
*ptr
, *vptr
;
1690 struct list vertical_families
= LIST_INIT( vertical_families
);
1692 LIST_FOR_EACH_ENTRY_SAFE( family
, next
, &font_list
, Family
, entry
)
1694 if (family
->FamilyName
[0] != '@') continue;
1695 list_remove( &family
->entry
);
1696 list_add_tail( &vertical_families
, &family
->entry
);
1699 ptr
= list_head( &font_list
);
1700 vptr
= list_head( &vertical_families
);
1703 family
= LIST_ENTRY( ptr
, Family
, entry
);
1704 vert_family
= LIST_ENTRY( vptr
, Family
, entry
);
1705 if (strcmpiW( family
->FamilyName
, vert_family
->FamilyName
+ 1 ) > 0)
1707 list_remove( vptr
);
1708 list_add_before( ptr
, vptr
);
1709 vptr
= list_head( &vertical_families
);
1711 else ptr
= list_next( &font_list
, ptr
);
1713 list_move_tail( &font_list
, &vertical_families
);
1716 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1718 DWORD size
, family_index
= 0;
1723 size
= sizeof(buffer
);
1724 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1726 WCHAR
*english_family
= NULL
;
1727 WCHAR
*family_name
= strdupW( buffer
);
1728 DWORD face_index
= 0;
1730 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1731 TRACE("opened family key %s\n", debugstr_w(family_name
));
1732 size
= sizeof(buffer
);
1733 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1734 english_family
= strdupW( buffer
);
1736 family
= create_family(family_name
, english_family
);
1740 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1741 subst
->from
.name
= strdupW(english_family
);
1742 subst
->from
.charset
= -1;
1743 subst
->to
.name
= strdupW(family_name
);
1744 subst
->to
.charset
= -1;
1745 add_font_subst(&font_subst_list
, subst
, 0);
1748 size
= sizeof(buffer
);
1749 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1751 WCHAR
*face_name
= strdupW( buffer
);
1754 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1756 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1757 RegCloseKey(hkey_face
);
1759 HeapFree( GetProcessHeap(), 0, face_name
);
1760 size
= sizeof(buffer
);
1762 RegCloseKey(hkey_family
);
1763 release_family( family
);
1764 size
= sizeof(buffer
);
1767 reorder_vertical_fonts();
1770 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1773 HKEY hkey_wine_fonts
;
1775 /* We don't want to create the fonts key as volatile, so open this first */
1776 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1777 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1778 if(ret
!= ERROR_SUCCESS
)
1780 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1784 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1785 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1786 RegCloseKey(hkey_wine_fonts
);
1790 static void add_face_to_cache(Face
*face
)
1792 HKEY hkey_family
, hkey_face
;
1793 WCHAR
*face_key_name
;
1795 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1796 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1797 if(face
->family
->EnglishName
)
1798 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1799 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1802 face_key_name
= face
->StyleName
;
1805 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1806 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1807 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1809 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1812 HeapFree(GetProcessHeap(), 0, face_key_name
);
1814 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1815 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1817 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1818 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1820 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1821 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1822 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1823 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1825 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1829 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1830 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1831 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1832 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1833 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1834 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1836 RegCloseKey(hkey_face
);
1837 RegCloseKey(hkey_family
);
1840 static void remove_face_from_cache( Face
*face
)
1844 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1848 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1852 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1853 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1854 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1855 RegDeleteKeyW( hkey_family
, face_key_name
);
1856 HeapFree(GetProcessHeap(), 0, face_key_name
);
1858 RegCloseKey(hkey_family
);
1861 static WCHAR
*prepend_at(WCHAR
*family
)
1868 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1870 strcpyW(str
+ 1, family
);
1871 HeapFree(GetProcessHeap(), 0, family
);
1875 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1877 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
) );
1878 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1880 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1886 else if (!strcmpiW( *name
, *english
))
1888 HeapFree( GetProcessHeap(), 0, *english
);
1894 *name
= prepend_at( *name
);
1895 *english
= prepend_at( *english
);
1899 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1902 WCHAR
*name
, *english_name
;
1904 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1906 family
= find_family_from_name( name
);
1910 family
= create_family( name
, english_name
);
1913 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1914 subst
->from
.name
= strdupW( english_name
);
1915 subst
->from
.charset
= -1;
1916 subst
->to
.name
= strdupW( name
);
1917 subst
->to
.charset
= -1;
1918 add_font_subst( &font_subst_list
, subst
, 0 );
1923 HeapFree( GetProcessHeap(), 0, name
);
1924 HeapFree( GetProcessHeap(), 0, english_name
);
1931 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1933 FT_Fixed version
= 0;
1936 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1937 if (header
) version
= header
->Font_Revision
;
1942 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1945 FT_ULong table_size
= 0;
1946 FT_WinFNT_HeaderRec winfnt_header
;
1948 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1949 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1951 /* fixup the flag for our fake-bold implementation. */
1952 if (!FT_IS_SCALABLE( ft_face
) &&
1953 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
1954 winfnt_header
.weight
> FW_NORMAL
)
1957 if (flags
== 0) flags
= NTM_REGULAR
;
1959 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1960 flags
|= NTM_PS_OPENTYPE
;
1965 static inline void get_bitmap_size( FT_Face ft_face
, Bitmap_Size
*face_size
)
1967 My_FT_Bitmap_Size
*size
;
1968 FT_WinFNT_HeaderRec winfnt_header
;
1970 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1971 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1972 size
->height
, size
->width
, size
->size
>> 6,
1973 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1974 face_size
->height
= size
->height
;
1975 face_size
->width
= size
->width
;
1976 face_size
->size
= size
->size
;
1977 face_size
->x_ppem
= size
->x_ppem
;
1978 face_size
->y_ppem
= size
->y_ppem
;
1980 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
1981 face_size
->internal_leading
= winfnt_header
.internal_leading
;
1982 if (winfnt_header
.external_leading
> 0 &&
1983 (face_size
->height
==
1984 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
1985 face_size
->height
= winfnt_header
.pixel_height
;
1989 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1994 FT_WinFNT_HeaderRec winfnt_header
;
1997 memset( fs
, 0, sizeof(*fs
) );
1999 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
2002 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
2003 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
2004 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
2005 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
2007 if (os2
->version
== 0)
2009 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
2010 fs
->fsCsb
[0] = FS_LATIN1
;
2012 fs
->fsCsb
[0] = FS_SYMBOL
;
2016 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
2017 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
2022 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
2024 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
2025 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
2026 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
2031 if (fs
->fsCsb
[0] == 0)
2033 /* let's see if we can find any interesting cmaps */
2034 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2036 switch (ft_face
->charmaps
[i
]->encoding
)
2038 case FT_ENCODING_UNICODE
:
2039 case FT_ENCODING_APPLE_ROMAN
:
2040 fs
->fsCsb
[0] |= FS_LATIN1
;
2042 case FT_ENCODING_MS_SYMBOL
:
2043 fs
->fsCsb
[0] |= FS_SYMBOL
;
2052 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2056 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
2059 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
2060 if (!face
->StyleName
) face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
2062 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
2063 if (flags
& ADDFONT_VERTICAL_FONT
)
2064 face
->FullName
= prepend_at( face
->FullName
);
2070 face
->file
= towstr( CP_UNIXCP
, file
);
2071 face
->font_data_ptr
= NULL
;
2072 face
->font_data_size
= 0;
2073 if (!stat( file
, &st
))
2075 face
->dev
= st
.st_dev
;
2076 face
->ino
= st
.st_ino
;
2082 face
->font_data_ptr
= font_data_ptr
;
2083 face
->font_data_size
= font_data_size
;
2086 face
->face_index
= face_index
;
2087 get_fontsig( ft_face
, &face
->fs
);
2088 face
->ntmFlags
= get_ntm_flags( ft_face
);
2089 face
->font_version
= get_font_version( ft_face
);
2091 if (FT_IS_SCALABLE( ft_face
))
2093 memset( &face
->size
, 0, sizeof(face
->size
) );
2094 face
->scalable
= TRUE
;
2098 get_bitmap_size( ft_face
, &face
->size
);
2099 face
->scalable
= FALSE
;
2102 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
2103 face
->flags
= flags
;
2104 face
->family
= NULL
;
2105 face
->cached_enum_data
= NULL
;
2107 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2108 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
2109 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
2110 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
2115 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2116 FT_Long face_index
, DWORD flags
)
2121 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
2122 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
2123 if (strlenW(family
->FamilyName
) >= LF_FACESIZE
)
2125 WARN("Ignoring %s because name is too long\n", debugstr_w(family
->FamilyName
));
2126 release_face( face
);
2127 release_family( family
);
2131 if (insert_face_in_family_list( face
, family
))
2133 if (flags
& ADDFONT_ADD_TO_CACHE
)
2134 add_face_to_cache( face
);
2136 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
2137 debugstr_w(face
->StyleName
));
2139 release_face( face
);
2140 release_family( family
);
2143 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2144 FT_Long face_index
, BOOL allow_bitmap
)
2152 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
2153 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
2157 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
2158 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
2163 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
2167 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2168 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
2170 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2174 if (!FT_IS_SFNT( ft_face
))
2176 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
2178 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2184 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
2185 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
2186 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
2188 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2189 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
2193 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2194 we don't want to load these. */
2195 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
2199 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
2201 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
2207 if (!ft_face
->family_name
|| !ft_face
->style_name
)
2209 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
2215 pFT_Done_Face( ft_face
);
2219 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
2222 FT_Long face_index
= 0, num_faces
;
2225 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2226 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
2228 #ifdef HAVE_CARBON_CARBON_H
2231 char **mac_list
= expand_mac_font(file
);
2234 BOOL had_one
= FALSE
;
2236 for(cursor
= mac_list
; *cursor
; cursor
++)
2239 AddFontToList(*cursor
, NULL
, 0, flags
);
2240 HeapFree(GetProcessHeap(), 0, *cursor
);
2242 HeapFree(GetProcessHeap(), 0, mac_list
);
2247 #endif /* HAVE_CARBON_CARBON_H */
2250 const DWORD FS_DBCS_MASK
= FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
;
2253 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
2254 if (!ft_face
) return 0;
2256 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
2258 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
2259 pFT_Done_Face(ft_face
);
2263 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
2266 get_fontsig(ft_face
, &fs
);
2267 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
2269 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
2270 flags
| ADDFONT_VERTICAL_FONT
);
2274 num_faces
= ft_face
->num_faces
;
2275 pFT_Done_Face(ft_face
);
2276 } while(num_faces
> ++face_index
);
2280 static int remove_font_resource( const char *file
, DWORD flags
)
2282 Family
*family
, *family_next
;
2283 Face
*face
, *face_next
;
2287 if (stat( file
, &st
) == -1) return 0;
2288 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2291 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2293 if (!face
->file
) continue;
2294 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2295 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2297 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2298 release_face( face
);
2302 release_family( family
);
2307 static void DumpFontList(void)
2312 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2313 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2314 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2315 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2317 TRACE(" %d", face
->size
.height
);
2323 static BOOL
map_font_family(const WCHAR
*orig
, const WCHAR
*repl
)
2325 Family
*family
= find_family_from_any_name(repl
);
2328 Family
*new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2329 if (new_family
!= NULL
)
2331 TRACE("mapping %s to %s\n", debugstr_w(repl
), debugstr_w(orig
));
2332 new_family
->FamilyName
= strdupW(orig
);
2333 new_family
->EnglishName
= NULL
;
2334 list_init(&new_family
->faces
);
2335 new_family
->replacement
= &family
->faces
;
2336 list_add_tail(&font_list
, &new_family
->entry
);
2340 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl
));
2344 /***********************************************************
2345 * The replacement list is a way to map an entire font
2346 * family onto another family. For example adding
2348 * [HKCU\Software\Wine\Fonts\Replacements]
2349 * "Wingdings"="Winedings"
2351 * would enumerate the Winedings font both as Winedings and
2352 * Wingdings. However if a real Wingdings font is present the
2353 * replacement does not take place.
2356 static void LoadReplaceList(void)
2359 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2363 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2364 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2366 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2367 &valuelen
, &datalen
, NULL
, NULL
);
2369 valuelen
++; /* returned value doesn't include room for '\0' */
2370 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2371 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2375 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
, &dlen
) == ERROR_SUCCESS
)
2377 /* "NewName"="Oldname" */
2378 if(!find_family_from_any_name(value
))
2380 if (type
== REG_MULTI_SZ
)
2382 WCHAR
*replace
= data
;
2385 if (map_font_family(value
, replace
))
2387 replace
+= strlenW(replace
) + 1;
2390 else if (type
== REG_SZ
)
2391 map_font_family(value
, data
);
2394 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2396 /* reset dlen and vlen */
2400 HeapFree(GetProcessHeap(), 0, data
);
2401 HeapFree(GetProcessHeap(), 0, value
);
2406 static const WCHAR
*font_links_list
[] =
2408 Lucida_Sans_Unicode
,
2409 Microsoft_Sans_Serif
,
2413 static const struct font_links_defaults_list
2415 /* Keyed off substitution for "MS Shell Dlg" */
2416 const WCHAR
*shelldlg
;
2417 /* Maximum of four substitutes, plus terminating NULL pointer */
2418 const WCHAR
*substitutes
[5];
2419 } font_links_defaults_list
[] =
2421 /* Non East-Asian */
2422 { Tahoma
, /* FIXME unverified ordering */
2423 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2425 /* Below lists are courtesy of
2426 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2430 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2432 /* Chinese Simplified */
2434 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2438 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2440 /* Chinese Traditional */
2442 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2447 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2449 SYSTEM_LINKS
*font_link
;
2451 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2453 if(!strcmpiW(font_link
->font_name
, name
))
2460 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2471 SYSTEM_LINKS
*font_link
;
2473 psub
= get_font_subst(&font_subst_list
, name
, -1);
2474 /* Don't store fonts that are only substitutes for other fonts */
2477 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2481 font_link
= find_font_link(name
);
2482 if (font_link
== NULL
)
2484 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2485 font_link
->font_name
= strdupW(name
);
2486 list_init(&font_link
->links
);
2487 list_add_tail(&system_links
, &font_link
->entry
);
2490 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2491 for (i
= 0; values
[i
] != NULL
; i
++)
2493 const struct list
*face_list
;
2494 CHILD_FONT
*child_font
;
2497 if (!strcmpiW(name
,value
))
2499 psub
= get_font_subst(&font_subst_list
, value
, -1);
2501 value
= psub
->to
.name
;
2502 family
= find_family_from_name(value
);
2506 /* Use first extant filename for this Family */
2507 face_list
= get_face_list_from_family(family
);
2508 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2512 file
= strrchrW(face
->file
, '/');
2521 face
= find_face_from_filename(file
, value
);
2524 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2528 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2529 child_font
->face
= face
;
2530 child_font
->font
= NULL
;
2531 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2532 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2533 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2534 child_font
->face
->face_index
);
2535 list_add_tail(&font_link
->links
, &child_font
->entry
);
2537 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2543 /*************************************************************
2546 static BOOL
init_system_links(void)
2550 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2551 WCHAR
*value
, *data
;
2552 WCHAR
*entry
, *next
;
2553 SYSTEM_LINKS
*font_link
, *system_font_link
;
2554 CHILD_FONT
*child_font
;
2555 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2556 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2557 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2562 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2564 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2565 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2566 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2567 val_len
= max_val
+ 1;
2568 data_len
= max_data
;
2570 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2572 psub
= get_font_subst(&font_subst_list
, value
, -1);
2573 /* Don't store fonts that are only substitutes for other fonts */
2576 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2579 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2580 font_link
->font_name
= strdupW(value
);
2581 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2582 list_init(&font_link
->links
);
2583 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2586 CHILD_FONT
*child_font
;
2588 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2590 next
= entry
+ strlenW(entry
) + 1;
2592 face_name
= strchrW(entry
, ',');
2596 while(isspaceW(*face_name
))
2599 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2601 face_name
= psub
->to
.name
;
2603 face
= find_face_from_filename(entry
, face_name
);
2606 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2610 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2611 child_font
->face
= face
;
2612 child_font
->font
= NULL
;
2613 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2614 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2615 TRACE("Adding file %s index %ld\n",
2616 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2617 list_add_tail(&font_link
->links
, &child_font
->entry
);
2619 list_add_tail(&system_links
, &font_link
->entry
);
2621 val_len
= max_val
+ 1;
2622 data_len
= max_data
;
2625 HeapFree(GetProcessHeap(), 0, value
);
2626 HeapFree(GetProcessHeap(), 0, data
);
2631 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2633 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2637 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2639 const FontSubst
*psub2
;
2640 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2642 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2644 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2645 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2647 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2648 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2650 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2652 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2658 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2661 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2662 system_font_link
->font_name
= strdupW(System
);
2663 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2664 list_init(&system_font_link
->links
);
2666 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2669 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2670 child_font
->face
= face
;
2671 child_font
->font
= NULL
;
2672 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2673 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2674 TRACE("Found Tahoma in %s index %ld\n",
2675 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2676 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2678 font_link
= find_font_link(Tahoma
);
2679 if (font_link
!= NULL
)
2681 CHILD_FONT
*font_link_entry
;
2682 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2684 CHILD_FONT
*new_child
;
2685 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2686 new_child
->face
= font_link_entry
->face
;
2687 new_child
->font
= NULL
;
2688 new_child
->face
->refcount
++;
2689 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2690 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2691 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2694 list_add_tail(&system_links
, &system_font_link
->entry
);
2698 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2701 struct dirent
*dent
;
2702 char path
[MAX_PATH
];
2704 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2706 dir
= opendir(dirname
);
2708 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2711 while((dent
= readdir(dir
)) != NULL
) {
2712 struct stat statbuf
;
2714 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2717 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2719 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2721 if(stat(path
, &statbuf
) == -1)
2723 WARN("Can't stat %s\n", debugstr_a(path
));
2726 if(S_ISDIR(statbuf
.st_mode
))
2727 ReadFontDir(path
, external_fonts
);
2730 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2731 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2732 AddFontToList(path
, NULL
, 0, addfont_flags
);
2739 #ifdef SONAME_LIBFONTCONFIG
2741 static BOOL fontconfig_enabled
;
2743 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2749 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2750 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2752 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2756 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2757 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2758 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2759 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2760 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2766 static void init_fontconfig(void)
2768 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2772 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2776 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2777 LOAD_FUNCPTR(FcConfigSubstitute
);
2778 LOAD_FUNCPTR(FcFontList
);
2779 LOAD_FUNCPTR(FcFontSetDestroy
);
2780 LOAD_FUNCPTR(FcInit
);
2781 LOAD_FUNCPTR(FcObjectSetAdd
);
2782 LOAD_FUNCPTR(FcObjectSetCreate
);
2783 LOAD_FUNCPTR(FcObjectSetDestroy
);
2784 LOAD_FUNCPTR(FcPatternCreate
);
2785 LOAD_FUNCPTR(FcPatternDestroy
);
2786 LOAD_FUNCPTR(FcPatternGetBool
);
2787 LOAD_FUNCPTR(FcPatternGetInteger
);
2788 LOAD_FUNCPTR(FcPatternGetString
);
2793 FcPattern
*pattern
= pFcPatternCreate();
2794 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2795 default_aa_flags
= parse_aa_pattern( pattern
);
2796 pFcPatternDestroy( pattern
);
2797 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2798 fontconfig_enabled
= TRUE
;
2802 static void load_fontconfig_fonts(void)
2811 if (!fontconfig_enabled
) return;
2813 pat
= pFcPatternCreate();
2814 os
= pFcObjectSetCreate();
2815 pFcObjectSetAdd(os
, FC_FILE
);
2816 pFcObjectSetAdd(os
, FC_SCALABLE
);
2817 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2818 pFcObjectSetAdd(os
, FC_RGBA
);
2819 fontset
= pFcFontList(NULL
, pat
, os
);
2820 if(!fontset
) return;
2821 for(i
= 0; i
< fontset
->nfont
; i
++) {
2825 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2828 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2830 /* We're just interested in OT/TT fonts for now, so this hack just
2831 picks up the scalable fonts without extensions .pf[ab] to save time
2832 loading every other font */
2834 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2836 TRACE("not scalable\n");
2840 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2841 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2843 len
= strlen( file
);
2844 if(len
< 4) continue;
2845 ext
= &file
[ len
- 3 ];
2846 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2847 AddFontToList(file
, NULL
, 0,
2848 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2850 pFcFontSetDestroy(fontset
);
2851 pFcObjectSetDestroy(os
);
2852 pFcPatternDestroy(pat
);
2855 #elif defined(HAVE_CARBON_CARBON_H)
2857 static void load_mac_font_callback(const void *value
, void *context
)
2859 CFStringRef pathStr
= value
;
2863 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2864 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2865 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2867 TRACE("font file %s\n", path
);
2868 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2870 HeapFree(GetProcessHeap(), 0, path
);
2873 static void load_mac_fonts(void)
2875 CFStringRef removeDupesKey
;
2876 CFBooleanRef removeDupesValue
;
2877 CFDictionaryRef options
;
2878 CTFontCollectionRef col
;
2880 CFMutableSetRef paths
;
2883 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2884 removeDupesValue
= kCFBooleanTrue
;
2885 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2886 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2887 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2888 if (options
) CFRelease(options
);
2891 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2895 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2899 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2903 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2906 WARN("CFSetCreateMutable failed\n");
2911 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2913 CTFontDescriptorRef desc
;
2922 desc
= CFArrayGetValueAtIndex(descs
, i
);
2924 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2925 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2926 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2927 if (!font
) continue;
2929 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2936 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2938 if (status
!= noErr
) continue;
2940 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2943 ext
= CFURLCopyPathExtension(url
);
2946 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2947 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2956 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2958 if (!path
) continue;
2960 CFSetAddValue(paths
, path
);
2966 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2972 static char *get_data_dir_path( LPCWSTR file
)
2974 char *unix_name
= NULL
;
2975 const char *data_dir
= wine_get_data_dir();
2977 if (!data_dir
) data_dir
= wine_get_build_dir();
2981 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2983 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2984 strcpy(unix_name
, data_dir
);
2985 strcat(unix_name
, "/fonts/");
2987 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2992 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2995 char *unix_name
= get_data_dir_path( file
);
2999 EnterCriticalSection( &freetype_cs
);
3000 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3001 LeaveCriticalSection( &freetype_cs
);
3002 HeapFree(GetProcessHeap(), 0, unix_name
);
3007 static char *get_winfonts_dir_path(LPCWSTR file
)
3009 static const WCHAR slashW
[] = {'\\','\0'};
3010 WCHAR windowsdir
[MAX_PATH
];
3012 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3013 strcatW(windowsdir
, fontsW
);
3014 strcatW(windowsdir
, slashW
);
3015 strcatW(windowsdir
, file
);
3016 return wine_get_unix_file_name( windowsdir
);
3019 static void load_system_fonts(void)
3022 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
3023 const WCHAR
* const *value
;
3025 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3028 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3029 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3030 strcatW(windowsdir
, fontsW
);
3031 for(value
= SystemFontValues
; *value
; value
++) {
3032 dlen
= sizeof(data
);
3033 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
3037 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3038 if((unixname
= wine_get_unix_file_name(pathW
))) {
3039 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3040 HeapFree(GetProcessHeap(), 0, unixname
);
3043 load_font_from_data_dir(data
);
3050 /*************************************************************
3052 * This adds registry entries for any externally loaded fonts
3053 * (fonts from fontconfig or FontDirs). It also deletes entries
3054 * of no longer existing fonts.
3057 static void update_reg_entries(void)
3059 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3065 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3067 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3068 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3069 ERR("Can't create Windows font reg key\n");
3073 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3074 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3075 ERR("Can't create Windows font reg key\n");
3079 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
3080 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
3081 ERR("Can't create external font reg key\n");
3085 /* enumerate the fonts and add external ones to the two keys */
3087 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
3088 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
3090 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
3094 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3095 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3096 strcpyW(valueW
, face
->FullName
);
3100 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3101 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3102 strcpyW(valueW
, family
->FamilyName
);
3105 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
3106 path
= wine_get_dos_file_name( buffer
);
3107 HeapFree( GetProcessHeap(), 0, buffer
);
3111 else if ((file
= strrchrW(face
->file
, '/')))
3116 len
= strlenW(file
) + 1;
3117 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3118 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3119 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3121 HeapFree(GetProcessHeap(), 0, path
);
3122 HeapFree(GetProcessHeap(), 0, valueW
);
3126 if(external_key
) RegCloseKey(external_key
);
3127 if(win9x_key
) RegCloseKey(win9x_key
);
3128 if(winnt_key
) RegCloseKey(winnt_key
);
3131 static void delete_external_font_keys(void)
3133 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3134 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
3138 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3139 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3140 ERR("Can't create Windows font reg key\n");
3144 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3145 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3146 ERR("Can't create Windows font reg key\n");
3150 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
3151 ERR("Can't create external font reg key\n");
3155 /* Delete all external fonts added last time */
3157 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3158 &valuelen
, &datalen
, NULL
, NULL
);
3159 valuelen
++; /* returned value doesn't include room for '\0' */
3160 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3161 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3163 dlen
= datalen
* sizeof(WCHAR
);
3166 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
3167 &dlen
) == ERROR_SUCCESS
) {
3169 RegDeleteValueW(winnt_key
, valueW
);
3170 RegDeleteValueW(win9x_key
, valueW
);
3171 /* reset dlen and vlen */
3175 HeapFree(GetProcessHeap(), 0, data
);
3176 HeapFree(GetProcessHeap(), 0, valueW
);
3178 /* Delete the old external fonts key */
3179 RegCloseKey(external_key
);
3180 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
3183 if(win9x_key
) RegCloseKey(win9x_key
);
3184 if(winnt_key
) RegCloseKey(winnt_key
);
3187 /*************************************************************
3188 * WineEngAddFontResourceEx
3191 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3197 if (ft_handle
) /* do it only if we have freetype up and running */
3201 EnterCriticalSection( &freetype_cs
);
3203 if((unixname
= wine_get_unix_file_name(file
)))
3205 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3207 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3208 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
3209 HeapFree(GetProcessHeap(), 0, unixname
);
3211 if (!ret
&& !strchrW(file
, '\\')) {
3212 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3213 if ((unixname
= get_winfonts_dir_path( file
)))
3215 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3216 HeapFree(GetProcessHeap(), 0, unixname
);
3218 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3219 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3221 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3222 HeapFree(GetProcessHeap(), 0, unixname
);
3226 LeaveCriticalSection( &freetype_cs
);
3231 /*************************************************************
3232 * WineEngAddFontMemResourceEx
3235 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3239 if (ft_handle
) /* do it only if we have freetype up and running */
3241 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
3243 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
3244 memcpy(pFontCopy
, pbFont
, cbFont
);
3246 EnterCriticalSection( &freetype_cs
);
3247 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3248 LeaveCriticalSection( &freetype_cs
);
3252 TRACE("AddFontToList failed\n");
3253 HeapFree(GetProcessHeap(), 0, pFontCopy
);
3256 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3257 * For now return something unique but quite random
3259 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
3260 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
3267 /*************************************************************
3268 * WineEngRemoveFontResourceEx
3271 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3277 if (ft_handle
) /* do it only if we have freetype up and running */
3281 EnterCriticalSection( &freetype_cs
);
3283 if ((unixname
= wine_get_unix_file_name(file
)))
3285 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3287 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3288 ret
= remove_font_resource( unixname
, addfont_flags
);
3289 HeapFree(GetProcessHeap(), 0, unixname
);
3291 if (!ret
&& !strchrW(file
, '\\'))
3293 if ((unixname
= get_winfonts_dir_path( file
)))
3295 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3296 HeapFree(GetProcessHeap(), 0, unixname
);
3298 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3300 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3301 HeapFree(GetProcessHeap(), 0, unixname
);
3305 LeaveCriticalSection( &freetype_cs
);
3310 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3316 if (!font_file
) return NULL
;
3318 file_len
= strlenW( font_file
);
3320 if (font_path
&& font_path
[0])
3322 int path_len
= strlenW( font_path
);
3323 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3324 if (!fullname
) return NULL
;
3325 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3326 fullname
[path_len
] = '\\';
3327 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3331 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3332 if (!len
) return NULL
;
3333 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3334 if (!fullname
) return NULL
;
3335 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3338 unix_name
= wine_get_unix_file_name( fullname
);
3339 HeapFree( GetProcessHeap(), 0, fullname
);
3343 #include <pshpack1.h>
3346 WORD num_of_resources
;
3350 CHAR dfCopyright
[60];
3356 WORD dfInternalLeading
;
3357 WORD dfExternalLeading
;
3365 BYTE dfPitchAndFamily
;
3376 CHAR szFaceName
[LF_FACESIZE
];
3379 #include <poppack.h>
3381 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3382 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3384 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3386 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3388 WCHAR
*name
, *english_name
;
3390 NEWTEXTMETRICEXW ntm
;
3393 if (!ft_face
) return FALSE
;
3394 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3395 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3396 pFT_Done_Face( ft_face
);
3398 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3399 release_face( face
);
3400 HeapFree( GetProcessHeap(), 0, name
);
3401 HeapFree( GetProcessHeap(), 0, english_name
);
3403 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3405 memset( fd
, 0, sizeof(*fd
) );
3407 fd
->num_of_resources
= 1;
3409 fd
->dfVersion
= 0x200;
3410 fd
->dfSize
= sizeof(*fd
);
3411 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3412 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3413 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3415 fd
->dfHorizRes
= 72;
3416 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3417 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3418 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3419 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3420 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3421 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3422 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3423 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3425 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3426 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3427 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3428 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3429 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3430 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3431 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3432 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3433 fd
->dfWidthBytes
= 0;
3435 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3437 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3442 #define NE_FFLAGS_LIBMODULE 0x8000
3443 #define NE_OSFLAGS_WINDOWS 0x02
3445 static const char dos_string
[0x40] = "This is a TrueType resource file";
3446 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3448 #include <pshpack2.h>
3469 struct ne_typeinfo fontdir_type
;
3470 struct ne_nameinfo fontdir_name
;
3471 struct ne_typeinfo scalable_type
;
3472 struct ne_nameinfo scalable_name
;
3474 BYTE fontdir_res_name
[8];
3477 #include <poppack.h>
3479 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3483 DWORD size
, written
;
3485 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3486 char *font_fileA
, *last_part
, *ext
;
3487 IMAGE_DOS_HEADER dos
;
3488 IMAGE_OS2_HEADER ne
=
3490 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3492 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3493 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3495 struct rsrc_tab rsrc_tab
=
3499 { 0, 0, 0x0c50, 0x2c, 0 },
3501 { 0, 0, 0x0c50, 0x8001, 0 },
3503 { 7,'F','O','N','T','D','I','R'}
3506 memset( &dos
, 0, sizeof(dos
) );
3507 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3508 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3510 /* import name is last part\0, resident name is last part without extension
3511 non-resident name is "FONTRES:" + lfFaceName */
3513 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3514 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3515 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3517 last_part
= strrchr( font_fileA
, '\\' );
3518 if (last_part
) last_part
++;
3519 else last_part
= font_fileA
;
3520 import_name_len
= strlen( last_part
) + 1;
3522 ext
= strchr( last_part
, '.' );
3523 if (ext
) res_name_len
= ext
- last_part
;
3524 else res_name_len
= import_name_len
- 1;
3526 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3528 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3529 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3530 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3531 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3533 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3535 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3536 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3537 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3538 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3540 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3541 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3545 HeapFree( GetProcessHeap(), 0, font_fileA
);
3549 memcpy( ptr
, &dos
, sizeof(dos
) );
3550 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3551 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3553 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3554 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3556 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3557 *ptr
++ = res_name_len
;
3558 memcpy( ptr
, last_part
, res_name_len
);
3560 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3561 *ptr
++ = import_name_len
;
3562 memcpy( ptr
, last_part
, import_name_len
);
3564 ptr
= start
+ ne
.ne_nrestab
;
3565 *ptr
++ = non_res_name_len
;
3566 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3567 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3569 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3570 memcpy( ptr
, font_fileA
, font_file_len
);
3572 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3573 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3575 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3576 if (file
!= INVALID_HANDLE_VALUE
)
3578 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3580 CloseHandle( file
);
3583 HeapFree( GetProcessHeap(), 0, start
);
3584 HeapFree( GetProcessHeap(), 0, font_fileA
);
3589 /*************************************************************
3590 * WineEngCreateScalableFontResource
3593 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3594 LPCWSTR font_file
, LPCWSTR font_path
)
3596 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3597 struct fontdir fontdir
;
3600 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3601 SetLastError( ERROR_INVALID_PARAMETER
);
3604 if (hidden
) fontdir
.dfType
|= 0x80;
3605 ret
= create_fot( resource
, font_file
, &fontdir
);
3608 HeapFree( GetProcessHeap(), 0, unix_name
);
3612 static const struct nls_update_font_list
3614 UINT ansi_cp
, oem_cp
;
3615 const char *oem
, *fixed
, *system
;
3616 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3617 /* these are for font substitutes */
3618 const char *shelldlg
, *tmsrmn
;
3619 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3623 const char *from
, *to
;
3624 } arial_0
, courier_new_0
, times_new_roman_0
;
3625 } nls_update_font_list
[] =
3627 /* Latin 1 (United States) */
3628 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3629 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3630 "Tahoma","Times New Roman",
3631 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3634 /* Latin 1 (Multilingual) */
3635 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3636 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3637 "Tahoma","Times New Roman", /* FIXME unverified */
3638 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3641 /* Eastern Europe */
3642 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3643 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3644 "Tahoma","Times New Roman", /* FIXME unverified */
3645 "Fixedsys,238", "System,238",
3646 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3647 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3648 { "Arial CE,0", "Arial,238" },
3649 { "Courier New CE,0", "Courier New,238" },
3650 { "Times New Roman CE,0", "Times New Roman,238" }
3653 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3654 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3655 "Tahoma","Times New Roman", /* FIXME unverified */
3656 "Fixedsys,204", "System,204",
3657 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3658 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3659 { "Arial Cyr,0", "Arial,204" },
3660 { "Courier New Cyr,0", "Courier New,204" },
3661 { "Times New Roman Cyr,0", "Times New Roman,204" }
3664 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3665 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3666 "Tahoma","Times New Roman", /* FIXME unverified */
3667 "Fixedsys,161", "System,161",
3668 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3669 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3670 { "Arial Greek,0", "Arial,161" },
3671 { "Courier New Greek,0", "Courier New,161" },
3672 { "Times New Roman Greek,0", "Times New Roman,161" }
3675 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3676 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3677 "Tahoma","Times New Roman", /* FIXME unverified */
3678 "Fixedsys,162", "System,162",
3679 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3680 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3681 { "Arial Tur,0", "Arial,162" },
3682 { "Courier New Tur,0", "Courier New,162" },
3683 { "Times New Roman Tur,0", "Times New Roman,162" }
3686 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3687 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3688 "Tahoma","Times New Roman", /* FIXME unverified */
3689 "Fixedsys,177", "System,177",
3690 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3691 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3695 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3696 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3697 "Microsoft Sans Serif","Times New Roman",
3698 "Fixedsys,178", "System,178",
3699 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3700 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3704 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3705 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3706 "Tahoma","Times New Roman", /* FIXME unverified */
3707 "Fixedsys,186", "System,186",
3708 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3709 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3710 { "Arial Baltic,0", "Arial,186" },
3711 { "Courier New Baltic,0", "Courier New,186" },
3712 { "Times New Roman Baltic,0", "Times New Roman,186" }
3715 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3716 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3717 "Tahoma","Times New Roman", /* FIXME unverified */
3718 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3722 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3723 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3724 "Tahoma","Times New Roman", /* FIXME unverified */
3725 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3729 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3730 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3731 "MS UI Gothic","MS Serif",
3732 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3735 /* Chinese Simplified */
3736 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3737 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3738 "SimSun", "NSimSun",
3739 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3743 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3744 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3746 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3749 /* Chinese Traditional */
3750 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3751 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3752 "PMingLiU", "MingLiU",
3753 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3758 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3760 return ( ansi_cp
== 932 /* CP932 for Japanese */
3761 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3762 || ansi_cp
== 949 /* CP949 for Korean */
3763 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3766 static inline HKEY
create_fonts_NT_registry_key(void)
3770 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3771 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3775 static inline HKEY
create_fonts_9x_registry_key(void)
3779 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3780 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3784 static inline HKEY
create_config_fonts_registry_key(void)
3788 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3789 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3793 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3795 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3797 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3798 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3799 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3800 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3803 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3806 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3808 RegDeleteValueA(hkey
, name
);
3811 static void update_font_association_info(UINT current_ansi_codepage
)
3813 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3814 static const char *assoc_charset_subkey
= "Associated Charset";
3816 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3819 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3822 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3824 switch (current_ansi_codepage
)
3827 set_value_key(hsubkey
, "ANSI(00)", "NO");
3828 set_value_key(hsubkey
, "OEM(FF)", "NO");
3829 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3834 set_value_key(hsubkey
, "ANSI(00)", "YES");
3835 set_value_key(hsubkey
, "OEM(FF)", "YES");
3836 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3839 RegCloseKey(hsubkey
);
3842 /* TODO: Associated DefaultFonts */
3848 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3851 static void set_multi_value_key(HKEY hkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD len
)
3854 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (const BYTE
*)value
, len
);
3856 RegDeleteValueW(hkey
, name
);
3859 static void update_font_system_link_info(UINT current_ansi_codepage
)
3861 static const WCHAR system_link_simplified_chinese
[] =
3862 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3863 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3864 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3865 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3867 static const WCHAR system_link_traditional_chinese
[] =
3868 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3869 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3870 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3871 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3873 static const WCHAR system_link_japanese
[] =
3874 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3875 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3876 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3877 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3879 static const WCHAR system_link_korean
[] =
3880 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3881 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3882 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3883 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3885 static const WCHAR system_link_non_cjk
[] =
3886 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3887 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3888 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3889 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3893 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
3898 switch (current_ansi_codepage
)
3901 link
= system_link_japanese
;
3902 len
= sizeof(system_link_japanese
);
3905 link
= system_link_simplified_chinese
;
3906 len
= sizeof(system_link_simplified_chinese
);
3909 link
= system_link_korean
;
3910 len
= sizeof(system_link_korean
);
3913 link
= system_link_traditional_chinese
;
3914 len
= sizeof(system_link_traditional_chinese
);
3917 link
= system_link_non_cjk
;
3918 len
= sizeof(system_link_non_cjk
);
3920 set_multi_value_key(hkey
, Lucida_Sans_Unicode
, link
, len
);
3921 set_multi_value_key(hkey
, Microsoft_Sans_Serif
, link
, len
);
3922 set_multi_value_key(hkey
, Tahoma
, link
, len
);
3927 static void update_font_info(void)
3929 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3930 char buf
[40], cpbuf
[40];
3933 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3934 DWORD screen_dpi
= 96, font_dpi
= 0;
3937 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3938 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3939 &hkey
) == ERROR_SUCCESS
)
3941 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3945 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3948 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3950 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3951 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3952 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3953 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3954 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3956 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3957 if (is_dbcs_ansi_cp(ansi_cp
))
3958 use_default_fallback
= TRUE
;
3962 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3964 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3969 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3970 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3972 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3973 ansi_cp
, oem_cp
, screen_dpi
);
3975 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3976 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3979 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3983 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3984 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3986 hkey
= create_config_fonts_registry_key();
3987 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3988 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3989 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3992 hkey
= create_fonts_NT_registry_key();
3993 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3996 hkey
= create_fonts_9x_registry_key();
3997 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
4000 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
4002 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
4003 strlen(nls_update_font_list
[i
].shelldlg
)+1);
4004 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
4005 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
4007 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
4008 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
4009 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
4010 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
4011 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
4012 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
4013 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
4014 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
4016 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
4017 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
4018 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
4026 /* Delete the FontSubstitutes from other locales */
4027 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
4029 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
4030 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
4031 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
4037 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
4039 /* update locale dependent font association info and font system link info in registry.
4040 update only when codepages changed, not logpixels. */
4041 if (strcmp(buf
, cpbuf
) != 0)
4043 update_font_association_info(ansi_cp
);
4044 update_font_system_link_info(ansi_cp
);
4048 static BOOL
init_freetype(void)
4050 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
4053 "Wine cannot find the FreeType font library. To enable Wine to\n"
4054 "use TrueType fonts please install a version of FreeType greater than\n"
4055 "or equal to 2.0.5.\n"
4056 "http://www.freetype.org\n");
4060 #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;}
4062 LOAD_FUNCPTR(FT_Done_Face
)
4063 LOAD_FUNCPTR(FT_Get_Char_Index
)
4064 LOAD_FUNCPTR(FT_Get_First_Char
)
4065 LOAD_FUNCPTR(FT_Get_Next_Char
)
4066 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
4067 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
4068 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
4069 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
4070 LOAD_FUNCPTR(FT_Init_FreeType
)
4071 LOAD_FUNCPTR(FT_Library_Version
)
4072 LOAD_FUNCPTR(FT_Load_Glyph
)
4073 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
4074 LOAD_FUNCPTR(FT_Matrix_Multiply
)
4075 #ifndef FT_MULFIX_INLINED
4076 LOAD_FUNCPTR(FT_MulFix
)
4078 LOAD_FUNCPTR(FT_New_Face
)
4079 LOAD_FUNCPTR(FT_New_Memory_Face
)
4080 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
4081 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
4082 LOAD_FUNCPTR(FT_Outline_Transform
)
4083 LOAD_FUNCPTR(FT_Outline_Translate
)
4084 LOAD_FUNCPTR(FT_Render_Glyph
)
4085 LOAD_FUNCPTR(FT_Select_Charmap
)
4086 LOAD_FUNCPTR(FT_Set_Charmap
)
4087 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
4088 LOAD_FUNCPTR(FT_Vector_Length
)
4089 LOAD_FUNCPTR(FT_Vector_Transform
)
4090 LOAD_FUNCPTR(FT_Vector_Unit
)
4092 /* Don't warn if these ones are missing */
4093 pFT_Outline_Embolden
= wine_dlsym(ft_handle
, "FT_Outline_Embolden", NULL
, 0);
4094 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
4095 #ifdef FT_LCD_FILTER_H
4096 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
4099 if(pFT_Init_FreeType(&library
) != 0) {
4100 ERR("Can't init FreeType library\n");
4101 wine_dlclose(ft_handle
, NULL
, 0);
4105 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
4107 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
4108 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
4109 ((FT_Version
.minor
<< 8) & 0x00ff00) |
4110 ((FT_Version
.patch
) & 0x0000ff);
4112 font_driver
= &freetype_funcs
;
4117 "Wine cannot find certain functions that it needs inside the FreeType\n"
4118 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4119 "FreeType to at least version 2.1.4.\n"
4120 "http://www.freetype.org\n");
4121 wine_dlclose(ft_handle
, NULL
, 0);
4126 static void init_font_list(void)
4128 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
4129 static const WCHAR pathW
[] = {'P','a','t','h',0};
4131 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
4132 WCHAR windowsdir
[MAX_PATH
];
4134 const char *data_dir
;
4136 delete_external_font_keys();
4138 /* load the system bitmap fonts */
4139 load_system_fonts();
4141 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4142 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
4143 strcatW(windowsdir
, fontsW
);
4144 if((unixname
= wine_get_unix_file_name(windowsdir
)))
4146 ReadFontDir(unixname
, FALSE
);
4147 HeapFree(GetProcessHeap(), 0, unixname
);
4150 /* load the system truetype fonts */
4151 data_dir
= wine_get_data_dir();
4152 if (!data_dir
) data_dir
= wine_get_build_dir();
4153 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
4155 strcpy(unixname
, data_dir
);
4156 strcat(unixname
, "/fonts/");
4157 ReadFontDir(unixname
, TRUE
);
4158 HeapFree(GetProcessHeap(), 0, unixname
);
4161 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4162 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4163 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4165 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
4166 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
4167 &hkey
) == ERROR_SUCCESS
)
4169 LPWSTR data
, valueW
;
4170 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4171 &valuelen
, &datalen
, NULL
, NULL
);
4173 valuelen
++; /* returned value doesn't include room for '\0' */
4174 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
4175 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
4178 dlen
= datalen
* sizeof(WCHAR
);
4180 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
4181 &dlen
) == ERROR_SUCCESS
)
4183 if(data
[0] && (data
[1] == ':'))
4185 if((unixname
= wine_get_unix_file_name(data
)))
4187 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4188 HeapFree(GetProcessHeap(), 0, unixname
);
4191 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
4193 WCHAR pathW
[MAX_PATH
];
4194 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
4197 sprintfW(pathW
, fmtW
, windowsdir
, data
);
4198 if((unixname
= wine_get_unix_file_name(pathW
)))
4200 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4201 HeapFree(GetProcessHeap(), 0, unixname
);
4204 load_font_from_data_dir(data
);
4206 /* reset dlen and vlen */
4211 HeapFree(GetProcessHeap(), 0, data
);
4212 HeapFree(GetProcessHeap(), 0, valueW
);
4216 #ifdef SONAME_LIBFONTCONFIG
4217 load_fontconfig_fonts();
4218 #elif defined(HAVE_CARBON_CARBON_H)
4222 /* then look in any directories that we've specified in the config file */
4223 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4224 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
4230 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
4232 len
+= sizeof(WCHAR
);
4233 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
4234 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
4236 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
4237 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
4238 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
4239 TRACE( "got font path %s\n", debugstr_a(valueA
) );
4244 LPSTR next
= strchr( ptr
, ':' );
4245 if (next
) *next
++ = 0;
4246 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
4247 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
4249 strcpy( unixname
, home
);
4250 strcat( unixname
, ptr
+ 1 );
4251 ReadFontDir( unixname
, TRUE
);
4252 HeapFree( GetProcessHeap(), 0, unixname
);
4255 ReadFontDir( ptr
, TRUE
);
4258 HeapFree( GetProcessHeap(), 0, valueA
);
4260 HeapFree( GetProcessHeap(), 0, valueW
);
4266 static BOOL
move_to_front(const WCHAR
*name
)
4268 Family
*family
, *cursor2
;
4269 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
4271 if(!strcmpiW(family
->FamilyName
, name
))
4273 list_remove(&family
->entry
);
4274 list_add_head(&font_list
, &family
->entry
);
4281 static BOOL
set_default(const WCHAR
**name_list
)
4285 if (move_to_front(*name_list
)) return TRUE
;
4292 static void reorder_font_list(void)
4294 set_default( default_serif_list
);
4295 set_default( default_fixed_list
);
4296 set_default( default_sans_list
);
4299 /*************************************************************
4302 * Initialize FreeType library and create a list of available faces
4304 BOOL
WineEngInit(void)
4310 /* update locale dependent font info in registry */
4313 if(!init_freetype()) return FALSE
;
4315 #ifdef SONAME_LIBFONTCONFIG
4319 if (!RegOpenKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, KEY_READ
, &hkey
))
4321 static const WCHAR antialias_fake_bold_or_italic
[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4322 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4323 static const WCHAR true_options
[] = { 'y','Y','t','T','1',0 };
4327 size
= sizeof(buffer
);
4328 if (!RegQueryValueExW(hkey
, antialias_fake_bold_or_italic
, NULL
, &type
, (BYTE
*)buffer
, &size
) &&
4329 type
== REG_SZ
&& size
>= 1)
4331 antialias_fakes
= (strchrW(true_options
, buffer
[0]) != NULL
);
4336 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
4338 ERR("Failed to create font mutex\n");
4341 WaitForSingleObject(font_mutex
, INFINITE
);
4343 create_font_cache_key(&hkey_font_cache
, &disposition
);
4345 if(disposition
== REG_CREATED_NEW_KEY
)
4348 load_font_list_from_cache(hkey_font_cache
);
4350 reorder_font_list();
4357 if(disposition
== REG_CREATED_NEW_KEY
)
4358 update_reg_entries();
4360 init_system_links();
4362 ReleaseMutex(font_mutex
);
4366 /* Some fonts have large usWinDescent values, as a result of storing signed short
4367 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4368 some font generation tools. */
4369 static inline USHORT
get_fixed_windescent(USHORT windescent
)
4371 return abs((SHORT
)windescent
);
4374 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
4377 TT_HoriHeader
*pHori
;
4380 const LONG MAX_PPEM
= (1 << 16) - 1;
4382 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4383 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4385 if(height
== 0) height
= 16;
4387 /* Calc. height of EM square:
4389 * For +ve lfHeight we have
4390 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4391 * Re-arranging gives:
4392 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4394 * For -ve lfHeight we have
4396 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4397 * with il = winAscent + winDescent - units_per_em]
4402 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
4403 if(pOS2
->usWinAscent
+ windescent
== 0)
4404 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4405 pHori
->Ascender
- pHori
->Descender
);
4407 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4408 pOS2
->usWinAscent
+ windescent
);
4409 if(ppem
> MAX_PPEM
) {
4410 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4414 else if(height
>= -MAX_PPEM
)
4417 WARN("Ignoring too large height %d\n", height
);
4424 static struct font_mapping
*map_font_file( const char *name
)
4426 struct font_mapping
*mapping
;
4430 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4431 if (fstat( fd
, &st
) == -1) goto error
;
4433 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4435 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4437 mapping
->refcount
++;
4442 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4445 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4448 if (mapping
->data
== MAP_FAILED
)
4450 HeapFree( GetProcessHeap(), 0, mapping
);
4453 mapping
->refcount
= 1;
4454 mapping
->dev
= st
.st_dev
;
4455 mapping
->ino
= st
.st_ino
;
4456 mapping
->size
= st
.st_size
;
4457 list_add_tail( &mappings_list
, &mapping
->entry
);
4465 static void unmap_font_file( struct font_mapping
*mapping
)
4467 if (!--mapping
->refcount
)
4469 list_remove( &mapping
->entry
);
4470 munmap( mapping
->data
, mapping
->size
);
4471 HeapFree( GetProcessHeap(), 0, mapping
);
4475 static LONG
load_VDMX(GdiFont
*, LONG
);
4477 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4484 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4488 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4489 font
->mapping
= map_font_file( filename
);
4490 HeapFree( GetProcessHeap(), 0, filename
);
4493 WARN("failed to map %s\n", debugstr_w(face
->file
));
4496 data_ptr
= font
->mapping
->data
;
4497 data_size
= font
->mapping
->size
;
4501 data_ptr
= face
->font_data_ptr
;
4502 data_size
= face
->font_data_size
;
4505 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4507 ERR("FT_New_Face rets %d\n", err
);
4511 /* set it here, as load_VDMX needs it */
4512 font
->ft_face
= ft_face
;
4514 if(FT_IS_SCALABLE(ft_face
)) {
4515 /* load the VDMX table if we have one */
4516 font
->ppem
= load_VDMX(font
, height
);
4518 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4519 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4521 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4522 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4524 font
->ppem
= height
;
4525 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4526 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4532 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4534 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4535 a single face with the requested charset. The idea is to check if
4536 the selected font supports the current ANSI codepage, if it does
4537 return the corresponding charset, else return the first charset */
4540 int acp
= GetACP(), i
;
4544 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4546 const SYSTEM_LINKS
*font_link
;
4548 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4549 return csi
.ciCharset
;
4551 font_link
= find_font_link(family_name
);
4552 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4553 return csi
.ciCharset
;
4556 for(i
= 0; i
< 32; i
++) {
4558 if(face
->fs
.fsCsb
[0] & fs0
) {
4559 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4561 return csi
.ciCharset
;
4564 FIXME("TCI failing on %x\n", fs0
);
4568 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4569 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4571 return DEFAULT_CHARSET
;
4574 static GdiFont
*alloc_font(void)
4576 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4579 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4580 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4582 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4583 ret
->total_kern_pairs
= (DWORD
)-1;
4584 ret
->kern_pairs
= NULL
;
4585 ret
->instance_id
= alloc_font_handle(ret
);
4586 list_init(&ret
->child_fonts
);
4590 static void free_font(GdiFont
*font
)
4592 CHILD_FONT
*child
, *child_next
;
4595 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4597 list_remove(&child
->entry
);
4599 free_font(child
->font
);
4600 release_face( child
->face
);
4601 HeapFree(GetProcessHeap(), 0, child
);
4604 HeapFree(GetProcessHeap(), 0, font
->fileinfo
);
4605 free_font_handle(font
->instance_id
);
4606 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4607 if (font
->mapping
) unmap_font_file( font
->mapping
);
4608 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4609 HeapFree(GetProcessHeap(), 0, font
->potm
);
4610 HeapFree(GetProcessHeap(), 0, font
->name
);
4611 for (i
= 0; i
< font
->gmsize
; i
++)
4612 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4613 HeapFree(GetProcessHeap(), 0, font
->gm
);
4614 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4615 HeapFree(GetProcessHeap(), 0, font
);
4619 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4621 FT_Face ft_face
= font
->ft_face
;
4625 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4632 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4634 /* make sure value of len is the value freetype says it needs */
4637 FT_ULong needed
= 0;
4638 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4639 if( !err
&& needed
< len
) len
= needed
;
4641 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4644 TRACE("Can't find table %c%c%c%c\n",
4645 /* bytes were reversed */
4646 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4647 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4653 /*************************************************************
4656 * load the vdmx entry for the specified height
4659 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4660 ( ( (FT_ULong)_x4 << 24 ) | \
4661 ( (FT_ULong)_x3 << 16 ) | \
4662 ( (FT_ULong)_x2 << 8 ) | \
4665 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4692 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4696 BYTE devXRatio
, devYRatio
;
4697 USHORT numRecs
, numRatios
;
4698 DWORD result
, offset
= -1;
4702 result
= get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
4704 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4707 /* FIXME: need the real device aspect ratio */
4711 numRecs
= GET_BE_WORD(hdr
.numRecs
);
4712 numRatios
= GET_BE_WORD(hdr
.numRatios
);
4714 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
4715 for(i
= 0; i
< numRatios
; i
++) {
4718 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
4719 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4722 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4724 if (!ratio
.bCharSet
) continue;
4726 if((ratio
.xRatio
== 0 &&
4727 ratio
.yStartRatio
== 0 &&
4728 ratio
.yEndRatio
== 0) ||
4729 (devXRatio
== ratio
.xRatio
&&
4730 devYRatio
>= ratio
.yStartRatio
&&
4731 devYRatio
<= ratio
.yEndRatio
))
4735 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
4736 get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
4737 offset
= GET_BE_WORD(group_offset
);
4742 if(offset
== -1) return 0;
4744 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
4746 BYTE startsz
, endsz
;
4749 recs
= GET_BE_WORD(group
.recs
);
4750 startsz
= group
.startsz
;
4751 endsz
= group
.endsz
;
4753 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4755 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
4756 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
4757 if(result
== GDI_ERROR
) {
4758 FIXME("Failed to retrieve vTable\n");
4763 for(i
= 0; i
< recs
; i
++) {
4764 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4765 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4766 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4768 if(yMax
+ -yMin
== height
) {
4771 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4774 if(yMax
+ -yMin
> height
) {
4777 goto end
; /* failed */
4779 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4780 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4781 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4782 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4788 TRACE("ppem not found for height %d\n", height
);
4792 if(ppem
< startsz
|| ppem
> endsz
)
4798 for(i
= 0; i
< recs
; i
++) {
4800 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4802 if(yPelHeight
> ppem
)
4808 if(yPelHeight
== ppem
) {
4809 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4810 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4811 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4817 HeapFree(GetProcessHeap(), 0, vTable
);
4823 static void dump_gdi_font_list(void)
4827 TRACE("---------- Font Cache ----------\n");
4828 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4829 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4830 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4833 static void grab_font( GdiFont
*font
)
4835 if (!font
->refcount
++)
4837 list_remove( &font
->unused_entry
);
4838 unused_font_count
--;
4842 static void release_font( GdiFont
*font
)
4845 if (!--font
->refcount
)
4847 TRACE( "font %p\n", font
);
4849 /* add it to the unused list */
4850 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4851 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4853 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4854 TRACE( "freeing %p\n", font
);
4855 list_remove( &font
->entry
);
4856 list_remove( &font
->unused_entry
);
4859 else unused_font_count
++;
4861 if (TRACE_ON(font
)) dump_gdi_font_list();
4865 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4867 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4868 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4869 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4870 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4871 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4874 static void calc_hash(FONT_DESC
*pfd
)
4876 DWORD hash
= 0, *ptr
, two_chars
;
4880 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4882 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4884 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4886 pwc
= (WCHAR
*)&two_chars
;
4888 *pwc
= toupperW(*pwc
);
4890 *pwc
= toupperW(*pwc
);
4894 hash
^= !pfd
->can_use_bitmap
;
4898 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4905 fd
.can_use_bitmap
= can_use_bitmap
;
4908 /* try the in-use list */
4909 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4911 if(fontcmp(ret
, &fd
)) continue;
4912 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4913 list_remove( &ret
->entry
);
4914 list_add_head( &gdi_font_list
, &ret
->entry
);
4921 static void add_to_cache(GdiFont
*font
)
4923 static DWORD cache_num
= 1;
4925 font
->cache_num
= cache_num
++;
4926 list_add_head(&gdi_font_list
, &font
->entry
);
4927 TRACE( "font %p\n", font
);
4930 /*************************************************************
4931 * create_child_font_list
4933 static BOOL
create_child_font_list(GdiFont
*font
)
4936 SYSTEM_LINKS
*font_link
;
4937 CHILD_FONT
*font_link_entry
, *new_child
;
4941 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4942 font_name
= psub
? psub
->to
.name
: font
->name
;
4943 font_link
= find_font_link(font_name
);
4944 if (font_link
!= NULL
)
4946 TRACE("found entry in system list\n");
4947 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4949 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4950 new_child
->face
= font_link_entry
->face
;
4951 new_child
->font
= NULL
;
4952 new_child
->face
->refcount
++;
4953 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4954 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4959 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4960 * Sans Serif. This is how asian windows get default fallbacks for fonts
4962 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4963 font
->charset
!= OEM_CHARSET
&&
4964 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4966 font_link
= find_font_link(szDefaultFallbackLink
);
4967 if (font_link
!= NULL
)
4969 TRACE("found entry in default fallback list\n");
4970 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4972 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4973 new_child
->face
= font_link_entry
->face
;
4974 new_child
->font
= NULL
;
4975 new_child
->face
->refcount
++;
4976 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4977 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4986 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4988 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4990 if (pFT_Set_Charmap
)
4993 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4995 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4997 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4999 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
5001 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5002 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
5004 switch (ft_face
->charmaps
[i
]->platform_id
)
5007 cmap_def
= ft_face
->charmaps
[i
];
5009 case 0: /* Apple Unicode */
5010 cmap0
= ft_face
->charmaps
[i
];
5012 case 1: /* Macintosh */
5013 cmap1
= ft_face
->charmaps
[i
];
5016 cmap2
= ft_face
->charmaps
[i
];
5018 case 3: /* Microsoft */
5019 cmap3
= ft_face
->charmaps
[i
];
5024 if (cmap3
) /* prefer Microsoft cmap table */
5025 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
5027 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
5029 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
5031 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
5033 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
5035 return ft_err
== FT_Err_Ok
;
5038 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
5042 /*************************************************************
5045 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
5046 LPCWSTR output
, const DEVMODEW
*devmode
)
5048 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
5050 if (!physdev
) return FALSE
;
5051 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
5056 /*************************************************************
5059 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
5061 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5062 release_font( physdev
->font
);
5063 HeapFree( GetProcessHeap(), 0, physdev
);
5067 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
5069 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
5070 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
5071 const FT_Encoding
*encs
= regular_order
;
5073 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
5077 if (select_charmap( face
, *encs
)) break;
5083 #define GASP_GRIDFIT 0x01
5084 #define GASP_DOGRAY 0x02
5085 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
5087 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
5090 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
5091 WORD
*alloced
= NULL
, *ptr
= buf
;
5092 WORD num_recs
, version
;
5096 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
5097 if (size
== GDI_ERROR
) return FALSE
;
5098 if (size
< 4 * sizeof(WORD
)) return FALSE
;
5099 if (size
> sizeof(buf
))
5101 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
5102 if (!ptr
) return FALSE
;
5105 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
5107 version
= GET_BE_WORD( *ptr
++ );
5108 num_recs
= GET_BE_WORD( *ptr
++ );
5110 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
5112 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
5118 *flags
= GET_BE_WORD( *(ptr
+ 1) );
5119 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
5122 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
5126 HeapFree( GetProcessHeap(), 0, alloced
);
5130 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5132 const GSUB_ScriptList
*script
;
5133 const GSUB_Script
*deflt
= NULL
;
5135 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5137 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5138 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5140 const GSUB_Script
*scr
;
5143 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5144 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5146 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5148 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5154 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5158 const GSUB_LangSys
*Lang
;
5160 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5162 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5164 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5165 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5167 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5170 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5173 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5179 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5182 const GSUB_FeatureList
*feature
;
5183 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5185 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5186 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5188 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5189 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5191 const GSUB_Feature
*feat
;
5192 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5199 static const char* get_opentype_script(const GdiFont
*font
)
5202 * I am not sure if this is the correct way to generate our script tag
5205 switch (font
->charset
)
5207 case ANSI_CHARSET
: return "latn";
5208 case BALTIC_CHARSET
: return "latn"; /* ?? */
5209 case CHINESEBIG5_CHARSET
: return "hani";
5210 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5211 case GB2312_CHARSET
: return "hani";
5212 case GREEK_CHARSET
: return "grek";
5213 case HANGUL_CHARSET
: return "hang";
5214 case RUSSIAN_CHARSET
: return "cyrl";
5215 case SHIFTJIS_CHARSET
: return "kana";
5216 case TURKISH_CHARSET
: return "latn"; /* ?? */
5217 case VIETNAMESE_CHARSET
: return "latn";
5218 case JOHAB_CHARSET
: return "latn"; /* ?? */
5219 case ARABIC_CHARSET
: return "arab";
5220 case HEBREW_CHARSET
: return "hebr";
5221 case THAI_CHARSET
: return "thai";
5222 default: return "latn";
5226 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
5228 const GSUB_Header
*header
;
5229 const GSUB_Script
*script
;
5230 const GSUB_LangSys
*language
;
5231 const GSUB_Feature
*feature
;
5233 if (!font
->GSUB_Table
)
5236 header
= font
->GSUB_Table
;
5238 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5241 TRACE("Script not found\n");
5244 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5247 TRACE("Language not found\n");
5250 feature
= GSUB_get_feature(header
, language
, "vrt2");
5252 feature
= GSUB_get_feature(header
, language
, "vert");
5255 TRACE("vrt2/vert feature not found\n");
5261 static void fill_fileinfo_from_face( GdiFont
*font
, Face
*face
)
5263 WIN32_FILE_ATTRIBUTE_DATA info
;
5268 font
->fileinfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*font
->fileinfo
));
5272 len
= strlenW(face
->file
);
5273 font
->fileinfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font
->fileinfo
) + len
* sizeof(WCHAR
));
5274 if (GetFileAttributesExW(face
->file
, GetFileExInfoStandard
, &info
))
5276 font
->fileinfo
->writetime
= info
.ftLastWriteTime
;
5277 font
->fileinfo
->size
.QuadPart
= (LONGLONG
)info
.nFileSizeHigh
<< 32 | info
.nFileSizeLow
;
5278 strcpyW(font
->fileinfo
->path
, face
->file
);
5281 memset(font
->fileinfo
, 0, sizeof(*font
->fileinfo
) + len
* sizeof(WCHAR
));
5284 /*************************************************************
5285 * freetype_SelectFont
5287 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5289 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5291 Face
*face
, *best
, *best_bitmap
;
5292 Family
*family
, *last_resort_family
;
5293 const struct list
*face_list
;
5294 INT height
, width
= 0;
5295 unsigned int score
= 0, new_score
;
5296 signed int diff
= 0, newdiff
;
5297 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5301 FontSubst
*psub
= NULL
;
5302 DC
*dc
= get_dc_ptr( dev
->hdc
);
5303 const SYSTEM_LINKS
*font_link
;
5305 if (!hfont
) /* notification that the font has been changed by another driver */
5307 release_font( physdev
->font
);
5308 physdev
->font
= NULL
;
5309 release_dc_ptr( dc
);
5313 GetObjectW( hfont
, sizeof(lf
), &lf
);
5314 lf
.lfWidth
= abs(lf
.lfWidth
);
5316 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5318 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5319 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5320 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5323 if(dc
->GraphicsMode
== GM_ADVANCED
)
5325 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5326 /* Try to avoid not necessary glyph transformations */
5327 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5329 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5330 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5331 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5336 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5337 font scaling abilities. */
5338 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5339 dcmat
.eM21
= dcmat
.eM12
= 0;
5340 lf
.lfOrientation
= lf
.lfEscapement
;
5341 if (dc
->vport2WorldValid
)
5343 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5344 lf
.lfOrientation
= -lf
.lfOrientation
;
5345 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5346 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5350 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5351 dcmat
.eM21
, dcmat
.eM22
);
5354 EnterCriticalSection( &freetype_cs
);
5356 /* check the cache first */
5357 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5358 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5362 TRACE("not in cache\n");
5365 ret
->font_desc
.matrix
= dcmat
;
5366 ret
->font_desc
.lf
= lf
;
5367 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5368 calc_hash(&ret
->font_desc
);
5370 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5371 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5372 original value lfCharSet. Note this is a special case for
5373 Symbol and doesn't happen at least for "Wingdings*" */
5375 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5376 lf
.lfCharSet
= SYMBOL_CHARSET
;
5378 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5379 switch(lf
.lfCharSet
) {
5380 case DEFAULT_CHARSET
:
5381 csi
.fs
.fsCsb
[0] = 0;
5384 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5385 csi
.fs
.fsCsb
[0] = 0;
5391 if(lf
.lfFaceName
[0] != '\0') {
5392 CHILD_FONT
*font_link_entry
;
5393 LPWSTR FaceName
= lf
.lfFaceName
;
5395 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5398 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5399 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5400 if (psub
->to
.charset
!= -1)
5401 lf
.lfCharSet
= psub
->to
.charset
;
5404 /* We want a match on name and charset or just name if
5405 charset was DEFAULT_CHARSET. If the latter then
5406 we fixup the returned charset later in get_nearest_charset
5407 where we'll either use the charset of the current ansi codepage
5408 or if that's unavailable the first charset that the font supports.
5410 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5411 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5412 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5414 font_link
= find_font_link(family
->FamilyName
);
5415 face_list
= get_face_list_from_family(family
);
5416 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5417 if (!(face
->scalable
|| can_use_bitmap
))
5419 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5421 if (font_link
!= NULL
&&
5422 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5424 if (!csi
.fs
.fsCsb
[0])
5430 /* Search by full face name. */
5431 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5432 face_list
= get_face_list_from_family(family
);
5433 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5434 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5435 (face
->scalable
|| can_use_bitmap
))
5437 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5439 font_link
= find_font_link(family
->FamilyName
);
5440 if (font_link
!= NULL
&&
5441 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5448 * Try check the SystemLink list first for a replacement font.
5449 * We may find good replacements there.
5451 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5453 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5454 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5456 TRACE("found entry in system list\n");
5457 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5459 const SYSTEM_LINKS
*links
;
5461 face
= font_link_entry
->face
;
5462 if (!(face
->scalable
|| can_use_bitmap
))
5464 family
= face
->family
;
5465 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5467 links
= find_font_link(family
->FamilyName
);
5468 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5475 psub
= NULL
; /* substitution is no more relevant */
5477 /* If requested charset was DEFAULT_CHARSET then try using charset
5478 corresponding to the current ansi codepage */
5479 if (!csi
.fs
.fsCsb
[0])
5482 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5483 FIXME("TCI failed on codepage %d\n", acp
);
5484 csi
.fs
.fsCsb
[0] = 0;
5486 lf
.lfCharSet
= csi
.ciCharset
;
5489 want_vertical
= (lf
.lfFaceName
[0] == '@');
5491 /* Face families are in the top 4 bits of lfPitchAndFamily,
5492 so mask with 0xF0 before testing */
5494 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5495 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5496 strcpyW(lf
.lfFaceName
, defFixed
);
5497 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5498 strcpyW(lf
.lfFaceName
, defSerif
);
5499 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5500 strcpyW(lf
.lfFaceName
, defSans
);
5502 strcpyW(lf
.lfFaceName
, defSans
);
5503 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5504 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5505 font_link
= find_font_link(family
->FamilyName
);
5506 face_list
= get_face_list_from_family(family
);
5507 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5508 if (!(face
->scalable
|| can_use_bitmap
))
5510 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5512 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5518 last_resort_family
= NULL
;
5519 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5520 font_link
= find_font_link(family
->FamilyName
);
5521 face_list
= get_face_list_from_family(family
);
5522 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5523 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5524 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5525 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5528 if(can_use_bitmap
&& !last_resort_family
)
5529 last_resort_family
= family
;
5534 if(last_resort_family
) {
5535 family
= last_resort_family
;
5536 csi
.fs
.fsCsb
[0] = 0;
5540 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5541 face_list
= get_face_list_from_family(family
);
5542 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5543 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5544 csi
.fs
.fsCsb
[0] = 0;
5545 WARN("just using first face for now\n");
5548 if(can_use_bitmap
&& !last_resort_family
)
5549 last_resort_family
= family
;
5552 if(!last_resort_family
) {
5553 FIXME("can't find a single appropriate font - bailing\n");
5559 WARN("could only find a bitmap font - this will probably look awful!\n");
5560 family
= last_resort_family
;
5561 csi
.fs
.fsCsb
[0] = 0;
5564 it
= lf
.lfItalic
? 1 : 0;
5565 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5567 height
= lf
.lfHeight
;
5569 face
= best
= best_bitmap
= NULL
;
5570 font_link
= find_font_link(family
->FamilyName
);
5571 face_list
= get_face_list_from_family(family
);
5572 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5574 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5575 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5580 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5581 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5582 new_score
= (italic
^ it
) + (bold
^ bd
);
5583 if(!best
|| new_score
<= score
)
5585 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5586 italic
, bold
, it
, bd
);
5589 if(best
->scalable
&& score
== 0) break;
5593 newdiff
= height
- (signed int)(best
->size
.height
);
5595 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5596 if(!best_bitmap
|| new_score
< score
||
5597 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5599 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5602 if(score
== 0 && diff
== 0) break;
5609 face
= best
->scalable
? best
: best_bitmap
;
5610 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5611 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5614 height
= lf
.lfHeight
;
5618 if(csi
.fs
.fsCsb
[0]) {
5619 ret
->charset
= lf
.lfCharSet
;
5620 ret
->codepage
= csi
.ciACP
;
5623 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5625 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5626 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5628 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5630 if(!face
->scalable
) {
5631 /* Windows uses integer scaling factors for bitmap fonts */
5632 INT scale
, scaled_height
;
5633 GdiFont
*cachedfont
;
5635 /* FIXME: rotation of bitmap fonts is ignored */
5636 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5638 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5639 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5640 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5641 /* As we changed the matrix, we need to search the cache for the font again,
5642 * otherwise we might explode the cache. */
5643 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5644 TRACE("Found cached font after non-scalable matrix rescale!\n");
5649 calc_hash(&ret
->font_desc
);
5651 if (height
!= 0) height
= diff
;
5652 height
+= face
->size
.height
;
5654 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5655 scaled_height
= scale
* face
->size
.height
;
5656 /* Only jump to the next height if the difference <= 25% original height */
5657 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5658 /* The jump between unscaled and doubled is delayed by 1 */
5659 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5660 ret
->scale_y
= scale
;
5662 width
= face
->size
.x_ppem
>> 6;
5663 height
= face
->size
.y_ppem
>> 6;
5667 TRACE("font scale y: %f\n", ret
->scale_y
);
5669 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5678 fill_fileinfo_from_face( ret
, face
);
5679 ret
->ntmFlags
= face
->ntmFlags
;
5681 pick_charmap( ret
->ft_face
, ret
->charset
);
5683 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5684 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5685 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5686 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5687 create_child_font_list(ret
);
5689 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5691 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5692 if (length
!= GDI_ERROR
)
5694 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5695 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5696 TRACE("Loaded GSUB table of %i bytes\n",length
);
5697 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5698 if (!ret
->vert_feature
)
5700 TRACE("Vertical feature not found\n");
5701 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5702 ret
->GSUB_Table
= NULL
;
5706 ret
->aa_flags
= HIWORD( face
->flags
);
5708 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5714 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5716 switch (lf
.lfQuality
)
5718 case NONANTIALIASED_QUALITY
:
5719 case ANTIALIASED_QUALITY
:
5720 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5722 case CLEARTYPE_QUALITY
:
5723 case CLEARTYPE_NATURAL_QUALITY
:
5725 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5726 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5728 /* fixup the antialiasing flags for that font */
5731 case WINE_GGO_HRGB_BITMAP
:
5732 case WINE_GGO_HBGR_BITMAP
:
5733 case WINE_GGO_VRGB_BITMAP
:
5734 case WINE_GGO_VBGR_BITMAP
:
5735 if (is_subpixel_rendering_enabled()) break;
5736 *aa_flags
= GGO_GRAY4_BITMAP
;
5738 case GGO_GRAY2_BITMAP
:
5739 case GGO_GRAY4_BITMAP
:
5740 case GGO_GRAY8_BITMAP
:
5741 case WINE_GGO_GRAY16_BITMAP
:
5742 if ((!antialias_fakes
|| (!ret
->fake_bold
&& !ret
->fake_italic
)) && is_hinting_enabled())
5745 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5747 TRACE( "font %s %d aa disabled by GASP\n",
5748 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5749 *aa_flags
= GGO_BITMAP
;
5754 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5755 release_font( physdev
->font
);
5756 physdev
->font
= ret
;
5758 LeaveCriticalSection( &freetype_cs
);
5759 release_dc_ptr( dc
);
5760 return ret
? hfont
: 0;
5763 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5770 id
+= IDS_FIRST_SCRIPT
;
5771 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5772 if (!rsrc
) return 0;
5773 hMem
= LoadResource( gdi32_module
, rsrc
);
5774 if (!hMem
) return 0;
5776 p
= LockResource( hMem
);
5778 while (id
--) p
+= *p
+ 1;
5780 i
= min(LF_FACESIZE
- 1, *p
);
5781 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5786 static inline BOOL
is_complex_script_ansi_cp(UINT ansi_cp
)
5788 return (ansi_cp
== 874 /* Thai */
5789 || ansi_cp
== 1255 /* Hebrew */
5790 || ansi_cp
== 1256 /* Arabic */
5794 /***************************************************
5795 * create_enum_charset_list
5797 * This function creates charset enumeration list because in DEFAULT_CHARSET
5798 * case, the ANSI codepage's charset takes precedence over other charsets.
5799 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5800 * This function works as a filter other than DEFAULT_CHARSET case.
5802 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5807 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5808 csi
.fs
.fsCsb
[0] != 0) {
5809 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5810 list
->element
[n
].charset
= csi
.ciCharset
;
5811 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5814 else { /* charset is DEFAULT_CHARSET or invalid. */
5818 /* Set the current codepage's charset as the first element. */
5820 if (!is_complex_script_ansi_cp(acp
) &&
5821 TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5822 csi
.fs
.fsCsb
[0] != 0) {
5823 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5824 list
->element
[n
].charset
= csi
.ciCharset
;
5825 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5826 mask
|= csi
.fs
.fsCsb
[0];
5830 /* Fill out left elements. */
5831 for (i
= 0; i
< 32; i
++) {
5833 fs
.fsCsb
[0] = 1L << i
;
5835 if (fs
.fsCsb
[0] & mask
)
5836 continue; /* skip, already added. */
5837 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5838 continue; /* skip, this is an invalid fsCsb bit. */
5840 list
->element
[n
].mask
= fs
.fsCsb
[0];
5841 list
->element
[n
].charset
= csi
.ciCharset
;
5842 load_script_name( i
, list
->element
[n
].name
);
5843 mask
|= fs
.fsCsb
[0];
5847 /* add catch all mask for remaining bits */
5850 list
->element
[n
].mask
= ~mask
;
5851 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5852 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5861 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5862 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5867 if (face
->cached_enum_data
)
5870 *pelf
= face
->cached_enum_data
->elf
;
5871 *pntm
= face
->cached_enum_data
->ntm
;
5872 *ptype
= face
->cached_enum_data
->type
;
5876 font
= alloc_font();
5878 if(face
->scalable
) {
5882 height
= face
->size
.y_ppem
>> 6;
5883 width
= face
->size
.x_ppem
>> 6;
5885 font
->scale_y
= 1.0;
5887 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5893 font
->name
= strdupW( family_name
);
5894 font
->ntmFlags
= face
->ntmFlags
;
5896 if (get_outline_text_metrics(font
))
5898 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5900 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5901 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5902 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5904 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5905 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5907 lstrcpynW(pelf
->elfFullName
,
5908 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5910 lstrcpynW(pelf
->elfStyle
,
5911 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5916 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5918 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5919 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5920 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5922 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5924 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5926 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5927 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5930 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5931 pntm
->ntmFontSig
= face
->fs
;
5933 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5935 pelf
->elfLogFont
.lfEscapement
= 0;
5936 pelf
->elfLogFont
.lfOrientation
= 0;
5937 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5938 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5939 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5940 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5941 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5942 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5943 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5944 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5945 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5946 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5947 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5950 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5951 *ptype
|= TRUETYPE_FONTTYPE
;
5952 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5953 *ptype
|= DEVICE_FONTTYPE
;
5954 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5955 *ptype
|= RASTER_FONTTYPE
;
5957 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5958 if (face
->cached_enum_data
)
5960 face
->cached_enum_data
->elf
= *pelf
;
5961 face
->cached_enum_data
->ntm
= *pntm
;
5962 face
->cached_enum_data
->type
= *ptype
;
5968 static BOOL
family_matches(Family
*family
, const WCHAR
*face_name
)
5971 const struct list
*face_list
;
5973 if (!strcmpiW(face_name
, family
->FamilyName
)) return TRUE
;
5975 face_list
= get_face_list_from_family(family
);
5976 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5977 if (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
)) return TRUE
;
5982 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const WCHAR
*face_name
)
5984 if (!strcmpiW(face_name
, family_name
)) return TRUE
;
5986 return (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
));
5989 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5990 FONTENUMPROCW proc
, LPARAM lparam
, const WCHAR
*subst
)
5993 NEWTEXTMETRICEXW ntm
;
5997 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5998 for(i
= 0; i
< list
->total
; i
++) {
5999 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
6000 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
6001 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
6002 i
= list
->total
; /* break out of loop after enumeration */
6006 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
6007 /* use the DEFAULT_CHARSET case only if no other charset is present */
6008 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
6009 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
6010 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
6011 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
6012 if (!elf
.elfScript
[0])
6013 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
6015 /* Font Replacement */
6016 if (family
!= face
->family
)
6018 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
6020 strcpyW(elf
.elfFullName
, face
->FullName
);
6022 strcpyW(elf
.elfFullName
, family
->FamilyName
);
6025 strcpyW(elf
.elfLogFont
.lfFaceName
, subst
);
6026 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6027 debugstr_w(elf
.elfLogFont
.lfFaceName
),
6028 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
6029 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
6030 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
6031 ntm
.ntmTm
.ntmFlags
);
6032 /* release section before callback (FIXME) */
6033 LeaveCriticalSection( &freetype_cs
);
6034 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
6035 EnterCriticalSection( &freetype_cs
);
6040 /*************************************************************
6041 * freetype_EnumFonts
6043 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6047 const struct list
*face_list
;
6049 struct enum_charset_list enum_charsets
;
6053 lf
.lfCharSet
= DEFAULT_CHARSET
;
6054 lf
.lfPitchAndFamily
= 0;
6055 lf
.lfFaceName
[0] = 0;
6059 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
6061 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
6064 EnterCriticalSection( &freetype_cs
);
6065 if(plf
->lfFaceName
[0]) {
6066 WCHAR
*face_name
= plf
->lfFaceName
;
6067 FontSubst
*psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
6070 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
6071 debugstr_w(psub
->to
.name
));
6072 face_name
= psub
->to
.name
;
6075 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
6076 if (!family_matches(family
, face_name
)) continue;
6077 face_list
= get_face_list_from_family(family
);
6078 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
6079 if (!face_matches(family
->FamilyName
, face
, face_name
)) continue;
6080 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, psub
? psub
->from
.name
: NULL
)) return FALSE
;
6084 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
6085 face_list
= get_face_list_from_family(family
);
6086 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
6087 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, NULL
)) return FALSE
;
6090 LeaveCriticalSection( &freetype_cs
);
6094 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
6096 pt
->x
.value
= vec
->x
>> 6;
6097 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
6098 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
6099 pt
->y
.value
= vec
->y
>> 6;
6100 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
6101 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
6104 /***************************************************
6105 * According to the MSDN documentation on WideCharToMultiByte,
6106 * certain codepages cannot set the default_used parameter.
6107 * This returns TRUE if the codepage can set that parameter, false else
6108 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6110 static BOOL
codepage_sets_default_used(UINT codepage
)
6124 * GSUB Table handling functions
6127 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
6129 const GSUB_CoverageFormat1
* cf1
;
6133 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
6135 int count
= GET_BE_WORD(cf1
->GlyphCount
);
6137 TRACE("Coverage Format 1, %i glyphs\n",count
);
6138 for (i
= 0; i
< count
; i
++)
6139 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
6143 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
6145 const GSUB_CoverageFormat2
* cf2
;
6148 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
6150 count
= GET_BE_WORD(cf2
->RangeCount
);
6151 TRACE("Coverage Format 2, %i ranges\n",count
);
6152 for (i
= 0; i
< count
; i
++)
6154 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
6156 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
6157 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
6159 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
6160 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
6166 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
6171 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
6175 const GSUB_LookupList
*lookup
;
6176 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
6178 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
6179 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
6181 const GSUB_LookupTable
*look
;
6182 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
6183 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
6184 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
6185 if (GET_BE_WORD(look
->LookupType
) != 1)
6186 FIXME("We only handle SubType 1\n");
6191 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
6193 const GSUB_SingleSubstFormat1
*ssf1
;
6194 offset
= GET_BE_WORD(look
->SubTable
[j
]);
6195 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
6196 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
6198 int offset
= GET_BE_WORD(ssf1
->Coverage
);
6199 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
6200 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
6202 TRACE(" Glyph 0x%x ->",glyph
);
6203 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
6204 TRACE(" 0x%x\n",glyph
);
6209 const GSUB_SingleSubstFormat2
*ssf2
;
6213 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
6214 offset
= GET_BE_WORD(ssf1
->Coverage
);
6215 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
6216 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
6217 TRACE(" Coverage index %i\n",index
);
6220 TRACE(" Glyph is 0x%x ->",glyph
);
6221 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
6222 TRACE("0x%x\n",glyph
);
6232 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
6234 const GSUB_Header
*header
;
6235 const GSUB_Feature
*feature
;
6237 if (!font
->GSUB_Table
)
6240 header
= font
->GSUB_Table
;
6241 feature
= font
->vert_feature
;
6243 return GSUB_apply_feature(header
, feature
, glyph
);
6246 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
6250 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6251 WCHAR wc
= (WCHAR
)glyph
;
6253 BOOL
*default_used_pointer
;
6256 default_used_pointer
= NULL
;
6257 default_used
= FALSE
;
6258 if (codepage_sets_default_used(font
->codepage
))
6259 default_used_pointer
= &default_used
;
6260 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6262 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6263 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6268 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6269 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6273 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6275 if (glyph
< 0x100) glyph
+= 0xf000;
6276 /* there is a number of old pre-Unicode "broken" TTFs, which
6277 do have symbols at U+00XX instead of U+f0XX */
6278 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6279 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6281 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6286 /* helper for freetype_GetGlyphIndices */
6287 static FT_UInt
get_gdi_glyph_index(const GdiFont
*font
, UINT glyph
)
6289 WCHAR wc
= (WCHAR
)glyph
;
6290 BOOL default_used
= FALSE
;
6291 BOOL
*default_used_pointer
= NULL
;
6295 if(font
->ft_face
->charmap
->encoding
!= FT_ENCODING_NONE
)
6296 return get_glyph_index(font
, glyph
);
6298 if (codepage_sets_default_used(font
->codepage
))
6299 default_used_pointer
= &default_used
;
6300 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
)
6303 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6304 ret
= (unsigned char)wc
;
6309 ret
= (unsigned char)buf
;
6310 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6314 static FT_UInt
get_default_char_index(GdiFont
*font
)
6316 FT_UInt default_char
;
6318 if (FT_IS_SFNT(font
->ft_face
))
6320 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6321 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6326 get_text_metrics(font
, &textm
);
6327 default_char
= textm
.tmDefaultChar
;
6330 return default_char
;
6333 /*************************************************************
6334 * freetype_GetGlyphIndices
6336 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6338 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6341 BOOL got_default
= FALSE
;
6345 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6346 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6349 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6351 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6356 EnterCriticalSection( &freetype_cs
);
6358 for(i
= 0; i
< count
; i
++)
6360 pgi
[i
] = get_gdi_glyph_index(physdev
->font
, lpstr
[i
]);
6365 default_char
= get_default_char_index(physdev
->font
);
6368 pgi
[i
] = default_char
;
6371 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6373 LeaveCriticalSection( &freetype_cs
);
6377 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6379 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6380 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6383 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6385 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6386 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6389 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
6393 len
= pFT_Vector_Length(vec
);
6395 out
.x
= (vec
->x
<< 6) / len
;
6396 out
.y
= (vec
->y
<< 6) / len
;
6403 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
6409 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
6411 if(!pFT_Outline_Embolden
)
6414 strength
= MulDiv(ppem
, 1 << 6, 24);
6415 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
6417 TRACE("FT_Ouline_Embolden returns %d\n", err
);
6421 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
6422 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
6423 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
6424 metrics
->horiBearingX
= bbox
.xMin
;
6425 metrics
->horiBearingY
= bbox
.yMax
;
6426 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
6427 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
6431 static inline BYTE
get_max_level( UINT format
)
6435 case GGO_GRAY2_BITMAP
: return 4;
6436 case GGO_GRAY4_BITMAP
: return 16;
6437 case GGO_GRAY8_BITMAP
: return 64;
6442 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
6444 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6446 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[uchar
>> 8]+((uchar
>> 4) & 0x0f)]+ (uchar
& 0xf)];
6448 /* We only reach this code if typographical substitution did not occur */
6449 /* Type: U or Type: Tu */
6450 return (orientation
== 1 || orientation
== 3);
6453 static FT_Vector
get_advance_metric(GdiFont
*incoming_font
, GdiFont
*font
,
6454 const FT_Glyph_Metrics
*metrics
,
6455 const FT_Matrix
*transMat
, BOOL vertical_metrics
)
6458 FT_Fixed base_advance
, em_scale
= 0;
6459 BOOL fixed_pitch_full
= FALSE
;
6461 if (vertical_metrics
)
6462 base_advance
= metrics
->vertAdvance
;
6464 base_advance
= metrics
->horiAdvance
;
6466 adv
.x
= base_advance
;
6469 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6470 they have double halfwidth character width. E.g. if the font is 19 ppem,
6471 we return 20 (not 19) for fullwidth characters as we return 10 for
6472 halfwidth characters. */
6473 if(FT_IS_SCALABLE(incoming_font
->ft_face
) &&
6474 (incoming_font
->potm
|| get_outline_text_metrics(incoming_font
)) &&
6475 !(incoming_font
->potm
->otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6477 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16,
6478 incoming_font
->ft_face
->units_per_EM
);
6479 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6480 fixed_pitch_full
= (avg_advance
> 0 &&
6481 (base_advance
+ 63) >> 6 ==
6482 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
6483 if (fixed_pitch_full
&& !transMat
)
6484 adv
.x
= (avg_advance
* 2) << 6;
6488 pFT_Vector_Transform(&adv
, transMat
);
6489 if (fixed_pitch_full
&& adv
.y
== 0) {
6491 vec
.x
= incoming_font
->ntmAvgWidth
;
6493 pFT_Vector_Transform(&vec
, transMat
);
6494 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
6498 if (font
->fake_bold
) {
6502 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
6503 pFT_Vector_Transform(&vec
, transMat
);
6504 fake_bold_adv
= normalize_vector(&vec
);
6505 adv
.x
+= fake_bold_adv
.x
;
6506 adv
.y
+= fake_bold_adv
.y
;
6510 adv
.x
= (adv
.x
+ 63) & -64;
6511 adv
.y
= -((adv
.y
+ 63) & -64);
6515 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6517 TTPOLYGONHEADER
*pph
;
6519 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
6520 unsigned int pph_start
, cpfx
;
6523 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6525 /* Ignore contours containing one point */
6526 if (point
== outline
->contours
[contour
])
6533 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6537 pph
->dwType
= TT_POLYGON_TYPE
;
6538 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6540 needed
+= sizeof(*pph
);
6542 while (point
<= outline
->contours
[contour
])
6544 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6545 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6546 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6551 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6554 } while (point
<= outline
->contours
[contour
] &&
6555 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6556 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6557 /* At the end of a contour Windows adds the start point, but
6559 if (point
> outline
->contours
[contour
] &&
6560 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6563 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6566 else if (point
<= outline
->contours
[contour
] &&
6567 outline
->tags
[point
] & FT_Curve_Tag_On
)
6569 /* add closing pt for bezier */
6571 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6580 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6583 pph
->cb
= needed
- pph_start
;
6588 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6590 /* Convert the quadratic Beziers to cubic Beziers.
6591 The parametric eqn for a cubic Bezier is, from PLRM:
6592 r(t) = at^3 + bt^2 + ct + r0
6593 with the control points:
6598 A quadratic Bezier has the form:
6599 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6601 So equating powers of t leads to:
6602 r1 = 2/3 p1 + 1/3 p0
6603 r2 = 2/3 p1 + 1/3 p2
6604 and of course r0 = p0, r3 = p2
6606 int contour
, point
= 0, first_pt
;
6607 TTPOLYGONHEADER
*pph
;
6609 DWORD pph_start
, cpfx
, type
;
6610 FT_Vector cubic_control
[4];
6611 unsigned int needed
= 0;
6613 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6616 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6620 pph
->dwType
= TT_POLYGON_TYPE
;
6621 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6623 needed
+= sizeof(*pph
);
6625 while (point
<= outline
->contours
[contour
])
6627 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6628 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6629 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6633 if (type
== TT_PRIM_LINE
)
6636 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6642 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6645 /* FIXME: Possible optimization in endpoint calculation
6646 if there are two consecutive curves */
6647 cubic_control
[0] = outline
->points
[point
-1];
6648 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6650 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6651 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6652 cubic_control
[0].x
>>= 1;
6653 cubic_control
[0].y
>>= 1;
6655 if (point
+1 > outline
->contours
[contour
])
6656 cubic_control
[3] = outline
->points
[first_pt
];
6659 cubic_control
[3] = outline
->points
[point
+1];
6660 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
6662 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6663 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6664 cubic_control
[3].x
>>= 1;
6665 cubic_control
[3].y
>>= 1;
6668 /* r1 = 1/3 p0 + 2/3 p1
6669 r2 = 1/3 p2 + 2/3 p1 */
6670 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6671 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6672 cubic_control
[2] = cubic_control
[1];
6673 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6674 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6675 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6676 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6679 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6680 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6681 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6686 } while (point
<= outline
->contours
[contour
] &&
6687 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6688 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6689 /* At the end of a contour Windows adds the start point,
6690 but only for Beziers and we've already done that.
6692 if (point
<= outline
->contours
[contour
] &&
6693 outline
->tags
[point
] & FT_Curve_Tag_On
)
6695 /* This is the closing pt of a bezier, but we've already
6696 added it, so just inc point and carry on */
6704 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6707 pph
->cb
= needed
- pph_start
;
6712 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6714 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6715 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6718 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6720 FT_Face ft_face
= incoming_font
->ft_face
;
6721 GdiFont
*font
= incoming_font
;
6722 FT_Glyph_Metrics metrics
;
6723 FT_UInt glyph_index
;
6724 DWORD width
, height
, pitch
, needed
= 0;
6725 FT_Bitmap ft_bitmap
;
6727 INT left
, right
, top
= 0, bottom
= 0;
6729 INT origin_x
= 0, origin_y
= 0;
6731 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6732 double widthRatio
= 1.0;
6733 FT_Matrix transMat
= identityMat
;
6734 FT_Matrix transMatUnrotated
;
6735 FT_Matrix transMatTategaki
;
6736 BOOL needsTransform
= FALSE
;
6737 BOOL tategaki
= (font
->name
[0] == '@');
6738 BOOL vertical_metrics
;
6739 UINT original_index
;
6741 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6742 buflen
, buf
, lpmat
);
6744 TRACE("font transform %f %f %f %f\n",
6745 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6746 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6748 if(format
& GGO_GLYPH_INDEX
) {
6749 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6750 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6751 as glyph index. "Treasure Adventure Game" depends on this. */
6752 glyph_index
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6753 TRACE("translate glyph index %04x -> %04x\n", glyph
, glyph_index
);
6755 glyph_index
= glyph
;
6756 original_index
= glyph_index
;
6757 format
&= ~GGO_GLYPH_INDEX
;
6758 /* TODO: Window also turns off tategaki for glyphs passed in by index
6759 if their unicode code points fall outside of the range that is
6763 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6764 ft_face
= font
->ft_face
;
6765 original_index
= glyph_index
;
6766 if (!vert
&& tategaki
)
6767 tategaki
= check_unicode_tategaki(glyph
);
6770 if(format
& GGO_UNHINTED
) {
6771 load_flags
|= FT_LOAD_NO_HINTING
;
6772 format
&= ~GGO_UNHINTED
;
6775 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6776 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6777 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6778 font
->gmsize
* sizeof(GM
*));
6780 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6781 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6783 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6784 *abc
= FONT_GM(font
,original_index
)->abc
;
6785 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6786 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6787 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6788 return 1; /* FIXME */
6792 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6793 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6795 /* Scaling factor */
6800 get_text_metrics(font
, &tm
);
6802 widthRatio
= (double)font
->aveWidth
;
6803 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6806 widthRatio
= font
->scale_y
;
6808 /* Scaling transform */
6809 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6812 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6815 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6817 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6818 needsTransform
= TRUE
;
6821 /* Slant transform */
6822 if (font
->fake_italic
) {
6825 slantMat
.xx
= (1 << 16);
6826 slantMat
.xy
= ((1 << 16) >> 2);
6828 slantMat
.yy
= (1 << 16);
6829 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6830 needsTransform
= TRUE
;
6833 /* Rotation transform */
6834 transMatUnrotated
= transMat
;
6835 transMatTategaki
= transMat
;
6836 if(font
->orientation
|| tategaki
) {
6837 FT_Matrix rotationMat
;
6838 FT_Matrix taterotationMat
;
6841 double orient
= font
->orientation
/ 10.0;
6842 double tate_orient
= 0.f
;
6845 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6847 tate_orient
= font
->orientation
/10.0;
6851 angle
= FT_FixedFromFloat(orient
);
6852 pFT_Vector_Unit(&vecAngle
, angle
);
6853 rotationMat
.xx
= vecAngle
.x
;
6854 rotationMat
.xy
= -vecAngle
.y
;
6855 rotationMat
.yx
= -rotationMat
.xy
;
6856 rotationMat
.yy
= rotationMat
.xx
;
6858 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6863 angle
= FT_FixedFromFloat(tate_orient
);
6864 pFT_Vector_Unit(&vecAngle
, angle
);
6865 taterotationMat
.xx
= vecAngle
.x
;
6866 taterotationMat
.xy
= -vecAngle
.y
;
6867 taterotationMat
.yx
= -taterotationMat
.xy
;
6868 taterotationMat
.yy
= taterotationMat
.xx
;
6869 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6872 needsTransform
= TRUE
;
6875 /* World transform */
6876 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6879 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6880 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6881 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6882 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6883 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6884 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6885 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6886 needsTransform
= TRUE
;
6889 /* Extra transformation specified by caller */
6890 if (!is_identity_MAT2(lpmat
))
6893 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6894 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6895 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6896 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6897 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6898 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6899 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6900 needsTransform
= TRUE
;
6903 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6904 /* there is a freetype bug where vertical metrics are only
6905 properly scaled and correct in 2.4.0 or greater */
6906 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6907 vertical_metrics
= FALSE
;
6909 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6910 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6912 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6915 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6919 metrics
= ft_face
->glyph
->metrics
;
6920 if(font
->fake_bold
) {
6921 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
6922 metrics
.width
+= 1 << 6;
6925 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6926 * by the text metrics. The proper behavior is to clip the glyph metrics to
6927 * fit within the maximums specified in the text metrics. */
6928 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6929 get_bitmap_text_metrics(incoming_font
)) {
6930 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6931 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6932 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6933 metrics
.horiBearingY
= top
;
6934 metrics
.height
= top
- bottom
;
6936 /* TODO: Are we supposed to clip the width as well...? */
6937 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6940 if(!needsTransform
) {
6941 left
= (INT
)(metrics
.horiBearingX
) & -64;
6942 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6943 top
= (metrics
.horiBearingY
+ 63) & -64;
6944 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6945 adv
= get_advance_metric(incoming_font
, font
, &metrics
, NULL
, vertical_metrics
);
6946 gm
.gmCellIncX
= adv
.x
>> 6;
6950 abc
->abcA
= origin_x
>> 6;
6951 abc
->abcB
= metrics
.width
>> 6;
6959 for(xc
= 0; xc
< 2; xc
++) {
6960 for(yc
= 0; yc
< 2; yc
++) {
6961 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6962 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6963 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6964 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6965 if(xc
== 0 && yc
== 0) {
6966 left
= right
= vec
.x
;
6967 top
= bottom
= vec
.y
;
6969 if(vec
.x
< left
) left
= vec
.x
;
6970 else if(vec
.x
> right
) right
= vec
.x
;
6971 if(vec
.y
< bottom
) bottom
= vec
.y
;
6972 else if(vec
.y
> top
) top
= vec
.y
;
6977 right
= (right
+ 63) & -64;
6978 bottom
= bottom
& -64;
6979 top
= (top
+ 63) & -64;
6981 if (tategaki
&& (font
->potm
|| get_outline_text_metrics(font
)))
6983 if (vertical_metrics
)
6984 lsb
= metrics
.horiBearingY
+ metrics
.vertBearingY
;
6986 lsb
= metrics
.vertAdvance
+ (font
->potm
->otmDescent
<< 6);
6988 vec
.y
= font
->potm
->otmDescent
<< 6;
6989 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
6990 pFT_Vector_Transform(&vec
, &transMat
);
6991 origin_x
= (vec
.x
+ left
) & -64;
6992 origin_y
= (vec
.y
+ top
+ 63) & -64;
6998 lsb
= metrics
.horiBearingX
;
7001 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
7002 adv
= get_advance_metric(incoming_font
, font
, &metrics
, &transMat
, vertical_metrics
);
7003 gm
.gmCellIncX
= adv
.x
>> 6;
7004 gm
.gmCellIncY
= adv
.y
>> 6;
7006 adv
= get_advance_metric(incoming_font
, font
, &metrics
, &transMatUnrotated
, vertical_metrics
);
7010 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
7011 abc
->abcA
= vec
.x
>> 6;
7013 vec
.x
= metrics
.width
;
7015 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
7017 abc
->abcB
= vec
.x
>> 6;
7019 abc
->abcB
= -vec
.x
>> 6;
7022 width
= (right
- left
) >> 6;
7023 height
= (top
- bottom
) >> 6;
7024 gm
.gmBlackBoxX
= width
? width
: 1;
7025 gm
.gmBlackBoxY
= height
? height
: 1;
7026 gm
.gmptGlyphOrigin
.x
= origin_x
>> 6;
7027 gm
.gmptGlyphOrigin
.y
= origin_y
>> 6;
7028 if (!abc
->abcB
) abc
->abcB
= 1;
7029 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
7031 TRACE("%u,%u,%s,%d,%d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
7032 wine_dbgstr_point(&gm
.gmptGlyphOrigin
),
7033 gm
.gmCellIncX
, gm
.gmCellIncY
);
7035 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
7036 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
7038 FONT_GM(font
,original_index
)->gm
= gm
;
7039 FONT_GM(font
,original_index
)->abc
= *abc
;
7040 FONT_GM(font
,original_index
)->init
= TRUE
;
7043 if(format
== GGO_METRICS
)
7046 return 1; /* FIXME */
7049 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
7050 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
7052 TRACE("loaded a bitmap\n");
7058 pitch
= ((width
+ 31) >> 5) << 2;
7059 needed
= pitch
* height
;
7061 if(!buf
|| !buflen
) break;
7062 if (!needed
) return GDI_ERROR
; /* empty glyph */
7063 if (needed
> buflen
)
7066 switch(ft_face
->glyph
->format
) {
7067 case ft_glyph_format_bitmap
:
7069 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
7070 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
7071 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7073 if (!font
->fake_bold
)
7074 memcpy(dst
, src
, w
);
7078 for (x
= 0; x
< w
; x
++) {
7079 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
7081 dst
[x
+1] = (src
[x
] & 0x01) << 7;
7084 src
+= ft_face
->glyph
->bitmap
.pitch
;
7090 case ft_glyph_format_outline
:
7091 ft_bitmap
.width
= width
;
7092 ft_bitmap
.rows
= height
;
7093 ft_bitmap
.pitch
= pitch
;
7094 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
7095 ft_bitmap
.buffer
= buf
;
7098 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
7100 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
7102 /* Note: FreeType will only set 'black' bits for us. */
7103 memset(buf
, 0, needed
);
7104 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
7108 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
7113 case GGO_GRAY2_BITMAP
:
7114 case GGO_GRAY4_BITMAP
:
7115 case GGO_GRAY8_BITMAP
:
7116 case WINE_GGO_GRAY16_BITMAP
:
7118 unsigned int max_level
, row
, col
;
7121 pitch
= (width
+ 3) / 4 * 4;
7122 needed
= pitch
* height
;
7124 if(!buf
|| !buflen
) break;
7125 if (!needed
) return GDI_ERROR
; /* empty glyph */
7126 if (needed
> buflen
)
7129 max_level
= get_max_level( format
);
7131 switch(ft_face
->glyph
->format
) {
7132 case ft_glyph_format_bitmap
:
7134 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
7135 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7137 memset( buf
, 0, needed
);
7139 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++) {
7140 if (src
[x
/ 8] & masks
[x
% 8]) {
7142 if (font
->fake_bold
&& x
+1 < pitch
) dst
[x
+1] = max_level
;
7145 src
+= ft_face
->glyph
->bitmap
.pitch
;
7150 case ft_glyph_format_outline
:
7152 ft_bitmap
.width
= width
;
7153 ft_bitmap
.rows
= height
;
7154 ft_bitmap
.pitch
= pitch
;
7155 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
7156 ft_bitmap
.buffer
= buf
;
7159 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
7161 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
7163 memset(ft_bitmap
.buffer
, 0, buflen
);
7165 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
7167 if (max_level
!= 255)
7169 for (row
= 0, start
= buf
; row
< height
; row
++)
7171 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
7172 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
7180 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
7186 case WINE_GGO_HRGB_BITMAP
:
7187 case WINE_GGO_HBGR_BITMAP
:
7188 case WINE_GGO_VRGB_BITMAP
:
7189 case WINE_GGO_VBGR_BITMAP
:
7190 #ifdef FT_LCD_FILTER_H
7192 switch (ft_face
->glyph
->format
)
7194 case FT_GLYPH_FORMAT_BITMAP
:
7200 needed
= pitch
* height
;
7202 if (!buf
|| !buflen
) break;
7203 if (!needed
) return GDI_ERROR
; /* empty glyph */
7204 if (needed
> buflen
)
7207 memset(buf
, 0, buflen
);
7209 src
= ft_face
->glyph
->bitmap
.buffer
;
7210 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7212 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7215 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
7217 if ( src
[x
/ 8] & masks
[x
% 8] )
7219 ((unsigned int *)dst
)[x
] = ~0u;
7220 if (font
->fake_bold
&& x
+1 < width
) ((unsigned int *)dst
)[x
+1] = ~0u;
7230 case FT_GLYPH_FORMAT_OUTLINE
:
7234 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
7235 INT x_shift
, y_shift
;
7237 FT_Render_Mode render_mode
=
7238 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
7239 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
7241 if (!width
|| !height
)
7243 if (!buf
|| !buflen
) break;
7247 if ( render_mode
== FT_RENDER_MODE_LCD
)
7249 gm
.gmBlackBoxX
+= 2;
7250 gm
.gmptGlyphOrigin
.x
-= 1;
7255 gm
.gmBlackBoxY
+= 2;
7256 gm
.gmptGlyphOrigin
.y
+= 1;
7260 width
= gm
.gmBlackBoxX
;
7261 height
= gm
.gmBlackBoxY
;
7263 needed
= pitch
* height
;
7265 if (!buf
|| !buflen
) break;
7266 if (needed
> buflen
)
7269 memset(buf
, 0, buflen
);
7271 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
7273 if ( needsTransform
)
7274 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
7276 if ( pFT_Library_SetLcdFilter
)
7277 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
7278 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
7280 src
= ft_face
->glyph
->bitmap
.buffer
;
7281 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7282 src_width
= ft_face
->glyph
->bitmap
.width
;
7283 src_height
= ft_face
->glyph
->bitmap
.rows
;
7285 if ( render_mode
== FT_RENDER_MODE_LCD
)
7293 rgb_interval
= src_pitch
;
7298 x_shift
= ft_face
->glyph
->bitmap_left
- (left
>> 6);
7301 src
+= hmul
* -x_shift
;
7302 src_width
-= hmul
* -x_shift
;
7304 else if ( x_shift
> 0 )
7310 y_shift
= (top
>> 6) - ft_face
->glyph
->bitmap_top
;
7313 src
+= src_pitch
* vmul
* -y_shift
;
7314 src_height
-= vmul
* -y_shift
;
7316 else if ( y_shift
> 0 )
7318 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
7322 width
= min( width
, src_width
/ hmul
);
7323 height
= min( height
, src_height
/ vmul
);
7327 for ( x
= 0; x
< width
; x
++ )
7331 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
7332 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7333 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
7334 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7338 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
7339 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7340 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
7341 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7344 src
+= src_pitch
* vmul
;
7345 dst
+= pitch
/ sizeof(*dst
);
7352 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
7364 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7366 if(buflen
== 0) buf
= NULL
;
7368 if (needsTransform
&& buf
)
7369 pFT_Outline_Transform(outline
, &transMatTategaki
);
7371 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
7373 if (!buf
|| !buflen
)
7375 if (needed
> buflen
)
7378 get_native_glyph_outline(outline
, buflen
, buf
);
7383 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7384 if(buflen
== 0) buf
= NULL
;
7386 if (needsTransform
&& buf
)
7387 pFT_Outline_Transform(outline
, &transMat
);
7389 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
7391 if (!buf
|| !buflen
)
7393 if (needed
> buflen
)
7396 get_bezier_glyph_outline(outline
, buflen
, buf
);
7401 FIXME("Unsupported format %d\n", format
);
7408 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7410 FT_Face ft_face
= font
->ft_face
;
7411 FT_WinFNT_HeaderRec winfnt_header
;
7412 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7413 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7414 font
->potm
->otmSize
= size
;
7416 #define TM font->potm->otmTextMetrics
7417 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7419 TM
.tmHeight
= winfnt_header
.pixel_height
;
7420 TM
.tmAscent
= winfnt_header
.ascent
;
7421 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7422 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7423 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7424 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7425 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7426 TM
.tmWeight
= winfnt_header
.weight
;
7428 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7429 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7430 TM
.tmFirstChar
= winfnt_header
.first_char
;
7431 TM
.tmLastChar
= winfnt_header
.last_char
;
7432 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7433 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7434 TM
.tmItalic
= winfnt_header
.italic
;
7435 TM
.tmUnderlined
= font
->underline
;
7436 TM
.tmStruckOut
= font
->strikeout
;
7437 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7438 TM
.tmCharSet
= winfnt_header
.charset
;
7442 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7443 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7444 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7445 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7446 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7447 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7448 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7449 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7451 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7452 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7454 TM
.tmLastChar
= 255;
7455 TM
.tmDefaultChar
= 32;
7456 TM
.tmBreakChar
= 32;
7457 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7458 TM
.tmUnderlined
= font
->underline
;
7459 TM
.tmStruckOut
= font
->strikeout
;
7460 /* NB inverted meaning of TMPF_FIXED_PITCH */
7461 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
7462 TM
.tmCharSet
= font
->charset
;
7470 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7472 double scale_x
, scale_y
;
7476 scale_x
= (double)font
->aveWidth
;
7477 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7480 scale_x
= font
->scale_y
;
7482 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7483 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7485 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7486 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7488 SCALE_Y(ptm
->tmHeight
);
7489 SCALE_Y(ptm
->tmAscent
);
7490 SCALE_Y(ptm
->tmDescent
);
7491 SCALE_Y(ptm
->tmInternalLeading
);
7492 SCALE_Y(ptm
->tmExternalLeading
);
7493 SCALE_Y(ptm
->tmOverhang
);
7495 SCALE_X(ptm
->tmAveCharWidth
);
7496 SCALE_X(ptm
->tmMaxCharWidth
);
7502 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7504 double scale_x
, scale_y
;
7508 scale_x
= (double)font
->aveWidth
;
7509 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7512 scale_x
= font
->scale_y
;
7514 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7515 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7517 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7519 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7520 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7522 SCALE_Y(potm
->otmAscent
);
7523 SCALE_Y(potm
->otmDescent
);
7524 SCALE_Y(potm
->otmLineGap
);
7525 SCALE_Y(potm
->otmsCapEmHeight
);
7526 SCALE_Y(potm
->otmsXHeight
);
7527 SCALE_Y(potm
->otmrcFontBox
.top
);
7528 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7529 SCALE_X(potm
->otmrcFontBox
.left
);
7530 SCALE_X(potm
->otmrcFontBox
.right
);
7531 SCALE_Y(potm
->otmMacAscent
);
7532 SCALE_Y(potm
->otmMacDescent
);
7533 SCALE_Y(potm
->otmMacLineGap
);
7534 SCALE_X(potm
->otmptSubscriptSize
.x
);
7535 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7536 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7537 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7538 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7539 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7540 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7541 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7542 SCALE_Y(potm
->otmsStrikeoutSize
);
7543 SCALE_Y(potm
->otmsStrikeoutPosition
);
7544 SCALE_Y(potm
->otmsUnderscoreSize
);
7545 SCALE_Y(potm
->otmsUnderscorePosition
);
7551 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7555 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7557 /* Make sure that the font has sane width/height ratio */
7560 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7562 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7567 *ptm
= font
->potm
->otmTextMetrics
;
7568 scale_font_metrics(font
, ptm
);
7572 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7576 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7578 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7584 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7587 FT_Face ft_face
= font
->ft_face
;
7588 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7590 TT_HoriHeader
*pHori
;
7591 TT_Postscript
*pPost
;
7593 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7595 INT ascent
, descent
;
7598 TRACE("font=%p\n", font
);
7600 if(!FT_IS_SCALABLE(ft_face
))
7603 needed
= sizeof(*font
->potm
);
7605 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7606 family_nameW
= strdupW(font
->name
);
7608 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7611 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7612 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7614 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7616 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7619 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7620 face_nameW
= strdupW(font
->name
);
7622 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7623 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7625 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7628 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7629 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7630 full_nameW
= strdupW(fake_nameW
);
7632 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7634 /* These names should be read from the TT name table */
7636 /* length of otmpFamilyName */
7639 /* length of otmpFaceName */
7642 /* length of otmpStyleName */
7645 /* length of otmpFullName */
7649 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7651 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7653 FIXME("Can't find OS/2 table - not TT font?\n");
7657 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7659 FIXME("Can't find HHEA table - not TT font?\n");
7663 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7665 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",
7666 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7667 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7668 pOS2
->xAvgCharWidth
,
7669 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7670 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7671 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7673 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7674 font
->potm
->otmSize
= needed
;
7676 #define TM font->potm->otmTextMetrics
7678 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
7679 if(pOS2
->usWinAscent
+ windescent
== 0) {
7680 ascent
= pHori
->Ascender
;
7681 descent
= -pHori
->Descender
;
7683 ascent
= pOS2
->usWinAscent
;
7684 descent
= windescent
;
7687 font
->ntmCellHeight
= ascent
+ descent
;
7688 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7690 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7691 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7694 TM
.tmAscent
= font
->yMax
;
7695 TM
.tmDescent
= -font
->yMin
;
7696 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7698 TM
.tmAscent
= SCALE_Y(ascent
);
7699 TM
.tmDescent
= SCALE_Y(descent
);
7700 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7703 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7706 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7708 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7709 ((ascent
+ descent
) -
7710 (pHori
->Ascender
- pHori
->Descender
))));
7712 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7713 if (TM
.tmAveCharWidth
== 0) {
7714 TM
.tmAveCharWidth
= 1;
7716 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7717 TM
.tmWeight
= FW_REGULAR
;
7718 if (font
->fake_bold
) {
7719 TM
.tmAveCharWidth
++;
7720 TM
.tmMaxCharWidth
++;
7721 TM
.tmWeight
= FW_BOLD
;
7725 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7727 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7728 TM
.tmWeight
= pOS2
->usWeightClass
;
7730 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7731 TM
.tmWeight
= pOS2
->usWeightClass
;
7734 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7735 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7736 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7737 * symbol range to 0 - f0ff
7740 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7745 case 1255: /* Hebrew */
7746 TM
.tmLastChar
= 0xf896;
7748 case 1257: /* Baltic */
7749 TM
.tmLastChar
= 0xf8fd;
7752 TM
.tmLastChar
= 0xf0ff;
7754 TM
.tmBreakChar
= 0x20;
7755 TM
.tmDefaultChar
= 0x1f;
7759 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7760 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7762 if(pOS2
->usFirstCharIndex
<= 1)
7763 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7764 else if (pOS2
->usFirstCharIndex
> 0xff)
7765 TM
.tmBreakChar
= 0x20;
7767 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7768 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7770 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7771 TM
.tmUnderlined
= font
->underline
;
7772 TM
.tmStruckOut
= font
->strikeout
;
7774 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7775 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7776 (pOS2
->version
== 0xFFFFU
||
7777 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7778 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7780 TM
.tmPitchAndFamily
= 0;
7782 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7784 case PAN_FAMILY_SCRIPT
:
7785 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7788 case PAN_FAMILY_DECORATIVE
:
7789 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7794 case PAN_FAMILY_TEXT_DISPLAY
:
7795 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7796 /* which is clearly not what the panose spec says. */
7798 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7799 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7800 TM
.tmPitchAndFamily
= FF_MODERN
;
7803 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7808 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7811 case PAN_SERIF_COVE
:
7812 case PAN_SERIF_OBTUSE_COVE
:
7813 case PAN_SERIF_SQUARE_COVE
:
7814 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7815 case PAN_SERIF_SQUARE
:
7816 case PAN_SERIF_THIN
:
7817 case PAN_SERIF_BONE
:
7818 case PAN_SERIF_EXAGGERATED
:
7819 case PAN_SERIF_TRIANGLE
:
7820 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7823 case PAN_SERIF_NORMAL_SANS
:
7824 case PAN_SERIF_OBTUSE_SANS
:
7825 case PAN_SERIF_PERP_SANS
:
7826 case PAN_SERIF_FLARED
:
7827 case PAN_SERIF_ROUNDED
:
7828 TM
.tmPitchAndFamily
|= FF_SWISS
;
7835 if(FT_IS_SCALABLE(ft_face
))
7836 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7838 if(FT_IS_SFNT(ft_face
))
7840 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7841 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7843 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7846 TM
.tmCharSet
= font
->charset
;
7848 font
->potm
->otmFiller
= 0;
7849 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7850 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7851 if (font
->fake_italic
)
7852 font
->potm
->otmfsSelection
|= 1;
7853 if (font
->fake_bold
)
7854 font
->potm
->otmfsSelection
|= 1 << 5;
7855 font
->potm
->otmfsType
= pOS2
->fsType
;
7856 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7857 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7858 font
->potm
->otmItalicAngle
= 0; /* POST table */
7859 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7860 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7861 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7862 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7863 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7864 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7865 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7866 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7867 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7868 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7869 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7870 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7871 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7872 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7873 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7874 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7875 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7876 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7877 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7878 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7879 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7880 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7881 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7882 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7884 font
->potm
->otmsUnderscoreSize
= 0;
7885 font
->potm
->otmsUnderscorePosition
= 0;
7887 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7888 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7894 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7895 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7896 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7897 strcpyW((WCHAR
*)cp
, family_nameW
);
7899 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7900 strcpyW((WCHAR
*)cp
, style_nameW
);
7902 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7903 strcpyW((WCHAR
*)cp
, face_nameW
);
7905 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7906 strcpyW((WCHAR
*)cp
, full_nameW
);
7910 HeapFree(GetProcessHeap(), 0, style_nameW
);
7911 HeapFree(GetProcessHeap(), 0, family_nameW
);
7912 HeapFree(GetProcessHeap(), 0, face_nameW
);
7913 HeapFree(GetProcessHeap(), 0, full_nameW
);
7917 /*************************************************************
7918 * freetype_GetGlyphOutline
7920 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7921 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7923 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7929 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7930 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7934 EnterCriticalSection( &freetype_cs
);
7935 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7936 LeaveCriticalSection( &freetype_cs
);
7940 /*************************************************************
7941 * freetype_GetTextMetrics
7943 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7945 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7950 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7951 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7955 EnterCriticalSection( &freetype_cs
);
7956 ret
= get_text_metrics( physdev
->font
, metrics
);
7957 LeaveCriticalSection( &freetype_cs
);
7961 /*************************************************************
7962 * freetype_GetOutlineTextMetrics
7964 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7966 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7971 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7972 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7975 TRACE("font=%p\n", physdev
->font
);
7977 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7980 EnterCriticalSection( &freetype_cs
);
7982 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7984 if(potm
&& cbSize
>= physdev
->font
->potm
->otmSize
)
7986 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7987 scale_outline_font_metrics(physdev
->font
, potm
);
7989 ret
= physdev
->font
->potm
->otmSize
;
7991 LeaveCriticalSection( &freetype_cs
);
7995 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7997 child
->font
= alloc_font();
7998 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7999 if(!child
->font
->ft_face
)
8001 free_font(child
->font
);
8006 child
->font
->font_desc
= font
->font_desc
;
8007 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
8008 child
->font
->orientation
= font
->orientation
;
8009 child
->font
->scale_y
= font
->scale_y
;
8010 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
8011 child
->font
->base_font
= font
;
8012 TRACE("created child font %p for base %p\n", child
->font
, font
);
8016 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
8019 CHILD_FONT
*child_font
;
8022 font
= font
->base_font
;
8024 *linked_font
= font
;
8026 if((*glyph
= get_glyph_index(font
, c
)))
8029 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
8030 *vert
= (o
!= *glyph
);
8034 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
8036 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
8038 if(!child_font
->font
)
8039 if(!load_child_font(font
, child_font
))
8042 if(!child_font
->font
->ft_face
)
8044 g
= get_glyph_index(child_font
->font
, c
);
8046 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
8050 *linked_font
= child_font
->font
;
8061 /*************************************************************
8062 * freetype_GetCharWidth
8064 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
8066 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8070 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8074 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
8075 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
8078 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
8081 EnterCriticalSection( &freetype_cs
);
8082 for(c
= firstChar
; c
<= lastChar
; c
++) {
8083 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
8084 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8086 LeaveCriticalSection( &freetype_cs
);
8090 /*************************************************************
8091 * freetype_GetCharABCWidths
8093 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
8095 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8098 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8102 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
8103 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
8106 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
8109 EnterCriticalSection( &freetype_cs
);
8111 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
8112 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
8114 LeaveCriticalSection( &freetype_cs
);
8118 /*************************************************************
8119 * freetype_GetCharABCWidthsI
8121 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
8123 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8126 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8130 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
8131 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
8134 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
8138 EnterCriticalSection( &freetype_cs
);
8140 for(c
= 0; c
< count
; c
++, buffer
++)
8141 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
8142 &gm
, buffer
, 0, NULL
, &identity
);
8144 LeaveCriticalSection( &freetype_cs
);
8148 /*************************************************************
8149 * freetype_GetTextExtentExPoint
8151 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
8153 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8157 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8161 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
8162 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
8165 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
8168 EnterCriticalSection( &freetype_cs
);
8170 for (idx
= pos
= 0; idx
< count
; idx
++)
8172 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
8173 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8177 LeaveCriticalSection( &freetype_cs
);
8181 /*************************************************************
8182 * freetype_GetTextExtentExPointI
8184 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
8186 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8190 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8194 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
8195 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
8198 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
8201 EnterCriticalSection( &freetype_cs
);
8203 for (idx
= pos
= 0; idx
< count
; idx
++)
8205 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
8206 &gm
, &abc
, 0, NULL
, &identity
);
8207 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8211 LeaveCriticalSection( &freetype_cs
);
8215 /*************************************************************
8216 * freetype_GetFontData
8218 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
8220 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8224 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
8225 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
8228 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
8229 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
8230 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
8232 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
8235 /*************************************************************
8236 * freetype_GetTextFace
8238 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
8241 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8245 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
8246 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
8249 n
= strlenW(physdev
->font
->name
) + 1;
8252 lstrcpynW(str
, physdev
->font
->name
, count
);
8258 /*************************************************************
8259 * freetype_GetTextCharsetInfo
8261 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
8263 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8267 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
8268 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
8270 if (fs
) *fs
= physdev
->font
->fs
;
8271 return physdev
->font
->charset
;
8274 /* Retrieve a list of supported Unicode ranges for a given font.
8275 * Can be called with NULL gs to calculate the buffer size. Returns
8276 * the number of ranges found.
8278 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
8280 DWORD num_ranges
= 0;
8282 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8285 FT_ULong char_code
, char_code_prev
;
8288 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
8290 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8291 face
->num_glyphs
, glyph_code
, char_code
);
8293 if (!glyph_code
) return 0;
8297 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
8298 gs
->ranges
[0].cGlyphs
= 0;
8299 gs
->cGlyphsSupported
= 0;
8305 if (char_code
< char_code_prev
)
8307 ERR("expected increasing char code from FT_Get_Next_Char\n");
8310 if (char_code
- char_code_prev
> 1)
8315 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
8316 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
8317 gs
->cGlyphsSupported
++;
8322 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
8323 gs
->cGlyphsSupported
++;
8325 char_code_prev
= char_code
;
8326 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
8330 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
8335 /*************************************************************
8336 * freetype_GetFontUnicodeRanges
8338 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
8340 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8341 DWORD size
, num_ranges
;
8345 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
8346 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
8349 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
8350 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
8353 glyphset
->cbThis
= size
;
8354 glyphset
->cRanges
= num_ranges
;
8355 glyphset
->flAccel
= 0;
8360 /*************************************************************
8361 * freetype_FontIsLinked
8363 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
8365 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8370 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
8371 return dev
->funcs
->pFontIsLinked( dev
);
8375 EnterCriticalSection( &freetype_cs
);
8376 ret
= !list_empty(&physdev
->font
->child_fonts
);
8377 LeaveCriticalSection( &freetype_cs
);
8381 /*************************************************************************
8382 * GetRasterizerCaps (GDI32.@)
8384 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8386 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8387 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
8388 lprs
->nLanguageID
= 0;
8392 /*************************************************************
8393 * freetype_GetFontRealizationInfo
8395 static BOOL
freetype_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
8397 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8398 struct font_realization_info
*info
= ptr
;
8402 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
8403 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
8406 TRACE("(%p, %p)\n", physdev
->font
, info
);
8409 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8412 info
->cache_num
= physdev
->font
->cache_num
;
8413 info
->instance_id
= physdev
->font
->instance_id
;
8414 if (info
->size
== sizeof(*info
))
8417 info
->face_index
= physdev
->font
->ft_face
->face_index
;
8418 info
->simulations
= 0;
8419 if (physdev
->font
->fake_bold
)
8420 info
->simulations
|= 0x1;
8421 if (physdev
->font
->fake_italic
)
8422 info
->simulations
|= 0x2;
8428 /*************************************************************************
8429 * GetFontFileInfo (GDI32.@)
8431 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
, DWORD size
, DWORD
*needed
)
8433 struct font_handle_entry
*entry
= handle_entry( instance_id
);
8434 const GdiFont
*font
;
8438 SetLastError(ERROR_INVALID_PARAMETER
);
8443 *needed
= sizeof(*info
) + strlenW(font
->fileinfo
->path
) * sizeof(WCHAR
);
8446 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
8450 /* path is included too */
8451 memcpy(info
, font
->fileinfo
, *needed
);
8455 /*************************************************************************
8456 * Kerning support for TrueType fonts
8458 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8460 struct TT_kern_table
8466 struct TT_kern_subtable
8475 USHORT horizontal
: 1;
8477 USHORT cross_stream
: 1;
8478 USHORT override
: 1;
8479 USHORT reserved1
: 4;
8485 struct TT_format0_kern_subtable
8489 USHORT entrySelector
;
8500 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8501 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8502 const USHORT
*glyph_to_char
,
8503 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8506 const struct TT_kern_pair
*tt_kern_pair
;
8508 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8510 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8512 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8513 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8514 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8516 if (!kern_pair
|| !cPairs
)
8519 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8521 nPairs
= min(nPairs
, cPairs
);
8523 for (i
= 0; i
< nPairs
; i
++)
8525 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8526 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8527 /* this algorithm appears to better match what Windows does */
8528 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8529 if (kern_pair
->iKernAmount
< 0)
8531 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8532 kern_pair
->iKernAmount
-= font
->ppem
;
8534 else if (kern_pair
->iKernAmount
> 0)
8536 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8537 kern_pair
->iKernAmount
+= font
->ppem
;
8539 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8541 TRACE("left %u right %u value %d\n",
8542 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8546 TRACE("copied %u entries\n", nPairs
);
8550 /*************************************************************
8551 * freetype_GetKerningPairs
8553 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8557 const struct TT_kern_table
*tt_kern_table
;
8558 const struct TT_kern_subtable
*tt_kern_subtable
;
8560 USHORT
*glyph_to_char
;
8562 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8564 if (!(font
= physdev
->font
))
8566 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8567 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8571 EnterCriticalSection( &freetype_cs
);
8572 if (font
->total_kern_pairs
!= (DWORD
)-1)
8574 if (cPairs
&& kern_pair
)
8576 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8577 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8579 else cPairs
= font
->total_kern_pairs
;
8581 LeaveCriticalSection( &freetype_cs
);
8585 font
->total_kern_pairs
= 0;
8587 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8589 if (length
== GDI_ERROR
)
8591 TRACE("no kerning data in the font\n");
8592 LeaveCriticalSection( &freetype_cs
);
8596 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8599 WARN("Out of memory\n");
8600 LeaveCriticalSection( &freetype_cs
);
8604 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8606 /* build a glyph index to char code map */
8607 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8610 WARN("Out of memory allocating a glyph index to char code map\n");
8611 HeapFree(GetProcessHeap(), 0, buf
);
8612 LeaveCriticalSection( &freetype_cs
);
8616 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8622 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8624 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8625 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8629 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8631 /* FIXME: This doesn't match what Windows does: it does some fancy
8632 * things with duplicate glyph index to char code mappings, while
8633 * we just avoid overriding existing entries.
8635 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8636 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8638 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8645 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8646 for (n
= 0; n
<= 65535; n
++)
8647 glyph_to_char
[n
] = (USHORT
)n
;
8650 tt_kern_table
= buf
;
8651 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8652 TRACE("version %u, nTables %u\n",
8653 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8655 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8657 for (i
= 0; i
< nTables
; i
++)
8659 struct TT_kern_subtable tt_kern_subtable_copy
;
8661 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8662 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8663 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8665 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8666 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8667 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8669 /* According to the TrueType specification this is the only format
8670 * that will be properly interpreted by Windows and OS/2
8672 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8674 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8676 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8677 glyph_to_char
, NULL
, 0);
8678 font
->total_kern_pairs
+= new_chunk
;
8680 if (!font
->kern_pairs
)
8681 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8682 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8684 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8685 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8687 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8688 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8691 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8693 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8696 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8697 HeapFree(GetProcessHeap(), 0, buf
);
8699 if (cPairs
&& kern_pair
)
8701 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8702 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8704 else cPairs
= font
->total_kern_pairs
;
8706 LeaveCriticalSection( &freetype_cs
);
8710 static const struct gdi_dc_funcs freetype_funcs
=
8712 NULL
, /* pAbortDoc */
8713 NULL
, /* pAbortPath */
8714 NULL
, /* pAlphaBlend */
8715 NULL
, /* pAngleArc */
8718 NULL
, /* pBeginPath */
8719 NULL
, /* pBlendImage */
8721 NULL
, /* pCloseFigure */
8722 NULL
, /* pCreateCompatibleDC */
8723 freetype_CreateDC
, /* pCreateDC */
8724 freetype_DeleteDC
, /* pDeleteDC */
8725 NULL
, /* pDeleteObject */
8726 NULL
, /* pDeviceCapabilities */
8727 NULL
, /* pEllipse */
8729 NULL
, /* pEndPage */
8730 NULL
, /* pEndPath */
8731 freetype_EnumFonts
, /* pEnumFonts */
8732 NULL
, /* pEnumICMProfiles */
8733 NULL
, /* pExcludeClipRect */
8734 NULL
, /* pExtDeviceMode */
8735 NULL
, /* pExtEscape */
8736 NULL
, /* pExtFloodFill */
8737 NULL
, /* pExtSelectClipRgn */
8738 NULL
, /* pExtTextOut */
8739 NULL
, /* pFillPath */
8740 NULL
, /* pFillRgn */
8741 NULL
, /* pFlattenPath */
8742 freetype_FontIsLinked
, /* pFontIsLinked */
8743 NULL
, /* pFrameRgn */
8744 NULL
, /* pGdiComment */
8745 NULL
, /* pGetBoundsRect */
8746 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8747 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8748 freetype_GetCharWidth
, /* pGetCharWidth */
8749 NULL
, /* pGetDeviceCaps */
8750 NULL
, /* pGetDeviceGammaRamp */
8751 freetype_GetFontData
, /* pGetFontData */
8752 freetype_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
8753 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8754 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8755 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8756 NULL
, /* pGetICMProfile */
8757 NULL
, /* pGetImage */
8758 freetype_GetKerningPairs
, /* pGetKerningPairs */
8759 NULL
, /* pGetNearestColor */
8760 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8761 NULL
, /* pGetPixel */
8762 NULL
, /* pGetSystemPaletteEntries */
8763 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8764 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8765 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8766 freetype_GetTextFace
, /* pGetTextFace */
8767 freetype_GetTextMetrics
, /* pGetTextMetrics */
8768 NULL
, /* pGradientFill */
8769 NULL
, /* pIntersectClipRect */
8770 NULL
, /* pInvertRgn */
8772 NULL
, /* pModifyWorldTransform */
8774 NULL
, /* pOffsetClipRgn */
8775 NULL
, /* pOffsetViewportOrg */
8776 NULL
, /* pOffsetWindowOrg */
8777 NULL
, /* pPaintRgn */
8780 NULL
, /* pPolyBezier */
8781 NULL
, /* pPolyBezierTo */
8782 NULL
, /* pPolyDraw */
8783 NULL
, /* pPolyPolygon */
8784 NULL
, /* pPolyPolyline */
8785 NULL
, /* pPolygon */
8786 NULL
, /* pPolyline */
8787 NULL
, /* pPolylineTo */
8788 NULL
, /* pPutImage */
8789 NULL
, /* pRealizeDefaultPalette */
8790 NULL
, /* pRealizePalette */
8791 NULL
, /* pRectangle */
8792 NULL
, /* pResetDC */
8793 NULL
, /* pRestoreDC */
8794 NULL
, /* pRoundRect */
8796 NULL
, /* pScaleViewportExt */
8797 NULL
, /* pScaleWindowExt */
8798 NULL
, /* pSelectBitmap */
8799 NULL
, /* pSelectBrush */
8800 NULL
, /* pSelectClipPath */
8801 freetype_SelectFont
, /* pSelectFont */
8802 NULL
, /* pSelectPalette */
8803 NULL
, /* pSelectPen */
8804 NULL
, /* pSetArcDirection */
8805 NULL
, /* pSetBkColor */
8806 NULL
, /* pSetBkMode */
8807 NULL
, /* pSetDCBrushColor */
8808 NULL
, /* pSetDCPenColor */
8809 NULL
, /* pSetDIBColorTable */
8810 NULL
, /* pSetDIBitsToDevice */
8811 NULL
, /* pSetDeviceClipping */
8812 NULL
, /* pSetDeviceGammaRamp */
8813 NULL
, /* pSetLayout */
8814 NULL
, /* pSetMapMode */
8815 NULL
, /* pSetMapperFlags */
8816 NULL
, /* pSetPixel */
8817 NULL
, /* pSetPolyFillMode */
8818 NULL
, /* pSetROP2 */
8819 NULL
, /* pSetRelAbs */
8820 NULL
, /* pSetStretchBltMode */
8821 NULL
, /* pSetTextAlign */
8822 NULL
, /* pSetTextCharacterExtra */
8823 NULL
, /* pSetTextColor */
8824 NULL
, /* pSetTextJustification */
8825 NULL
, /* pSetViewportExt */
8826 NULL
, /* pSetViewportOrg */
8827 NULL
, /* pSetWindowExt */
8828 NULL
, /* pSetWindowOrg */
8829 NULL
, /* pSetWorldTransform */
8830 NULL
, /* pStartDoc */
8831 NULL
, /* pStartPage */
8832 NULL
, /* pStretchBlt */
8833 NULL
, /* pStretchDIBits */
8834 NULL
, /* pStrokeAndFillPath */
8835 NULL
, /* pStrokePath */
8836 NULL
, /* pUnrealizePalette */
8837 NULL
, /* pWidenPath */
8838 NULL
, /* wine_get_wgl_driver */
8839 GDI_PRIORITY_FONT_DRV
/* priority */
8842 #else /* HAVE_FREETYPE */
8844 struct font_fileinfo
;
8846 /*************************************************************************/
8848 BOOL
WineEngInit(void)
8853 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8855 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8859 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8861 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8865 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8867 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8871 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8872 LPCWSTR font_file
, LPCWSTR font_path
)
8878 /*************************************************************************
8879 * GetRasterizerCaps (GDI32.@)
8881 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8883 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8885 lprs
->nLanguageID
= 0;
8889 /*************************************************************************
8890 * GetFontFileInfo (GDI32.@)
8892 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
, DWORD size
, DWORD
*needed
)
8898 #endif /* HAVE_FREETYPE */