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 #ifndef WINE_FONT_DIR
218 #define WINE_FONT_DIR "fonts"
221 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
228 FT_Short internal_leading
;
231 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
232 So to let this compile on older versions of FreeType we'll define the
233 new structure here. */
235 FT_Short height
, width
;
236 FT_Pos size
, x_ppem
, y_ppem
;
242 NEWTEXTMETRICEXW ntm
;
246 typedef struct tagFace
{
248 unsigned int refcount
;
255 DWORD font_data_size
;
259 FT_Fixed font_version
;
261 Bitmap_Size size
; /* set if face is a bitmap */
262 DWORD flags
; /* ADDFONT flags */
263 struct tagFamily
*family
;
264 /* Cached data for Enum */
265 struct enum_data
*cached_enum_data
;
268 #define ADDFONT_EXTERNAL_FONT 0x01
269 #define ADDFONT_ALLOW_BITMAP 0x02
270 #define ADDFONT_ADD_TO_CACHE 0x04
271 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
272 #define ADDFONT_VERTICAL_FONT 0x10
273 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
275 typedef struct tagFamily
{
277 unsigned int refcount
;
281 struct list
*replacement
;
286 ABC abc
; /* metrics of the unrotated char */
302 typedef struct tagGdiFont GdiFont
;
304 #define FIRST_FONT_HANDLE 1
305 #define MAX_FONT_HANDLES 256
307 struct font_handle_entry
310 WORD generation
; /* generation count for reusing handle values */
313 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
314 static struct font_handle_entry
*next_free
;
315 static struct font_handle_entry
*next_unused
= font_handles
;
317 static inline DWORD
entry_to_handle( struct font_handle_entry
*entry
)
319 unsigned int idx
= entry
- font_handles
+ FIRST_FONT_HANDLE
;
320 return idx
| (entry
->generation
<< 16);
323 static inline struct font_handle_entry
*handle_entry( DWORD handle
)
325 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
327 if (idx
< MAX_FONT_HANDLES
)
329 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
330 return &font_handles
[idx
];
332 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
336 static DWORD
alloc_font_handle( void *obj
)
338 struct font_handle_entry
*entry
;
342 next_free
= entry
->obj
;
343 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
344 entry
= next_unused
++;
347 ERR( "out of realized font handles\n" );
351 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
352 return entry_to_handle( entry
);
355 static void free_font_handle( DWORD handle
)
357 struct font_handle_entry
*entry
;
359 if ((entry
= handle_entry( handle
)))
361 entry
->obj
= next_free
;
372 struct font_fileinfo
{
380 struct list unused_entry
;
381 unsigned int refcount
;
384 OUTLINETEXTMETRICW
*potm
;
385 DWORD total_kern_pairs
;
386 KERNINGPAIR
*kern_pairs
;
387 struct list child_fonts
;
389 /* the following members can be accessed without locking, they are never modified after creation */
391 struct font_mapping
*mapping
;
407 UINT ntmCellHeight
, ntmAvgWidth
;
411 const VOID
*vert_feature
;
414 struct font_fileinfo
*fileinfo
;
419 const WCHAR
*font_name
;
424 struct enum_charset_element
{
427 WCHAR name
[LF_FACESIZE
];
430 struct enum_charset_list
{
432 struct enum_charset_element element
[32];
435 #define GM_BLOCK_SIZE 128
436 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
438 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
439 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
440 static unsigned int unused_font_count
;
441 #define UNUSED_CACHE_SIZE 10
442 static struct list system_links
= LIST_INIT(system_links
);
444 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
446 static struct list font_list
= LIST_INIT(font_list
);
448 struct freetype_physdev
450 struct gdi_physdev dev
;
454 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
456 return (struct freetype_physdev
*)dev
;
459 static const struct gdi_dc_funcs freetype_funcs
;
461 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
462 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
463 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
465 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
466 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
467 'W','i','n','d','o','w','s','\\',
468 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
469 'F','o','n','t','s','\0'};
471 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
472 'W','i','n','d','o','w','s',' ','N','T','\\',
473 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
474 'F','o','n','t','s','\0'};
476 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
477 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
478 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
479 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
481 static const WCHAR
* const SystemFontValues
[] = {
488 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
489 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
491 /* Interesting and well-known (frequently-assumed!) font names */
492 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
493 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 };
494 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
495 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
496 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
497 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
498 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
499 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
501 static const WCHAR arial
[] = {'A','r','i','a','l',0};
502 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
503 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};
504 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};
505 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
506 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
507 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
508 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
509 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
510 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
512 static const WCHAR
*default_serif_list
[] =
516 bitstream_vera_serif
,
520 static const WCHAR
*default_fixed_list
[] =
524 bitstream_vera_sans_mono
,
528 static const WCHAR
*default_sans_list
[] =
541 typedef struct tagFontSubst
{
547 /* Registry font cache key and value names */
548 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
549 'F','o','n','t','s',0};
550 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
551 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
552 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
553 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
554 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
555 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
556 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
557 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
558 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
559 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
560 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
561 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
562 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
563 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
564 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
577 static struct list mappings_list
= LIST_INIT( mappings_list
);
579 static UINT default_aa_flags
;
580 static HKEY hkey_font_cache
;
581 static BOOL antialias_fakes
= TRUE
;
583 static CRITICAL_SECTION freetype_cs
;
584 static CRITICAL_SECTION_DEBUG critsect_debug
=
587 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
588 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
590 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
592 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
594 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
595 static BOOL use_default_fallback
= FALSE
;
597 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
*vert
);
598 static BOOL
get_outline_text_metrics(GdiFont
*font
);
599 static BOOL
get_bitmap_text_metrics(GdiFont
*font
);
600 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
601 static void remove_face_from_cache( Face
*face
);
603 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
604 'W','i','n','d','o','w','s',' ','N','T','\\',
605 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
606 'S','y','s','t','e','m','L','i','n','k',0};
608 /****************************************
609 * Notes on .fon files
611 * The fonts System, FixedSys and Terminal are special. There are typically multiple
612 * versions installed for different resolutions and codepages. Windows stores which one to use
613 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
615 * FIXEDFON.FON FixedSys
617 * OEMFONT.FON Terminal
618 * LogPixels Current dpi set by the display control panel applet
619 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
620 * also has a LogPixels value that appears to mirror this)
622 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
623 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
624 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
625 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
626 * so that makes sense.
628 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
629 * to be mapped into the registry on Windows 2000 at least).
632 * ega80woa.fon=ega80850.fon
633 * ega40woa.fon=ega40850.fon
634 * cga80woa.fon=cga80850.fon
635 * cga40woa.fon=cga40850.fon
638 /* These are all structures needed for the GSUB table */
640 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
656 GSUB_ScriptRecord ScriptRecord
[1];
662 } GSUB_LangSysRecord
;
667 GSUB_LangSysRecord LangSysRecord
[1];
671 WORD LookupOrder
; /* Reserved */
672 WORD ReqFeatureIndex
;
674 WORD FeatureIndex
[1];
680 } GSUB_FeatureRecord
;
684 GSUB_FeatureRecord FeatureRecord
[1];
688 WORD FeatureParams
; /* Reserved */
690 WORD LookupListIndex
[1];
709 } GSUB_CoverageFormat1
;
714 WORD StartCoverageIndex
;
720 GSUB_RangeRecord RangeRecord
[1];
721 } GSUB_CoverageFormat2
;
724 WORD SubstFormat
; /* = 1 */
727 } GSUB_SingleSubstFormat1
;
730 WORD SubstFormat
; /* = 2 */
734 }GSUB_SingleSubstFormat2
;
736 #ifdef HAVE_CARBON_CARBON_H
737 static char *find_cache_dir(void)
741 static char cached_path
[MAX_PATH
];
742 static const char *wine
= "/Wine", *fonts
= "/Fonts";
744 if(*cached_path
) return cached_path
;
746 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
749 WARN("can't create cached data folder\n");
752 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
755 WARN("can't create cached data path\n");
759 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
761 ERR("Could not create full path\n");
765 strcat(cached_path
, wine
);
767 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
769 WARN("Couldn't mkdir %s\n", cached_path
);
773 strcat(cached_path
, fonts
);
774 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
776 WARN("Couldn't mkdir %s\n", cached_path
);
783 /******************************************************************
786 * Extracts individual TrueType font files from a Mac suitcase font
787 * and saves them into the user's caches directory (see
789 * Returns a NULL terminated array of filenames.
791 * We do this because they are apps that try to read ttf files
792 * themselves and they don't like Mac suitcase files.
794 static char **expand_mac_font(const char *path
)
801 const char *filename
;
805 unsigned int size
, max_size
;
808 TRACE("path %s\n", path
);
810 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
813 WARN("failed to get ref\n");
817 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
820 TRACE("no data fork, so trying resource fork\n");
821 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
824 TRACE("unable to open resource fork\n");
831 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
834 CloseResFile(res_ref
);
838 out_dir
= find_cache_dir();
840 filename
= strrchr(path
, '/');
841 if(!filename
) filename
= path
;
844 /* output filename has the form out_dir/filename_%04x.ttf */
845 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
852 unsigned short *num_faces_ptr
, num_faces
, face
;
855 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
857 fond
= Get1IndResource(fond_res
, idx
);
859 TRACE("got fond resource %d\n", idx
);
862 fam_rec
= *(FamRec
**)fond
;
863 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
864 num_faces
= GET_BE_WORD(*num_faces_ptr
);
866 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
867 TRACE("num faces %04x\n", num_faces
);
868 for(face
= 0; face
< num_faces
; face
++, assoc
++)
871 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
872 unsigned short size
, font_id
;
875 size
= GET_BE_WORD(assoc
->fontSize
);
876 font_id
= GET_BE_WORD(assoc
->fontID
);
879 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
883 TRACE("trying to load sfnt id %04x\n", font_id
);
884 sfnt
= GetResource(sfnt_res
, font_id
);
887 TRACE("can't get sfnt resource %04x\n", font_id
);
891 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
896 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
898 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
899 if(fd
!= -1 || errno
== EEXIST
)
903 unsigned char *sfnt_data
;
906 sfnt_data
= *(unsigned char**)sfnt
;
907 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
911 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
914 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
916 ret
.array
[ret
.size
++] = output
;
920 WARN("unable to create %s\n", output
);
921 HeapFree(GetProcessHeap(), 0, output
);
924 ReleaseResource(sfnt
);
927 ReleaseResource(fond
);
930 CloseResFile(res_ref
);
935 #endif /* HAVE_CARBON_CARBON_H */
937 static inline BOOL
is_win9x(void)
939 return GetVersion() & 0x80000000;
942 This function builds an FT_Fixed from a double. It fails if the absolute
943 value of the float number is greater than 32768.
945 static inline FT_Fixed
FT_FixedFromFloat(double f
)
951 This function builds an FT_Fixed from a FIXED. It simply put f.value
952 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
954 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
956 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
959 static BOOL
is_hinting_enabled(void)
961 static int enabled
= -1;
965 /* Use the >= 2.2.0 function if available */
966 if (pFT_Get_TrueType_Engine_Type
)
968 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
969 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
971 else enabled
= FALSE
;
972 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
977 static BOOL
is_subpixel_rendering_enabled( void )
979 #ifdef FT_LCD_FILTER_H
980 static int enabled
= -1;
983 enabled
= (pFT_Library_SetLcdFilter
&&
984 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
985 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
994 static const struct list
*get_face_list_from_family(const Family
*family
)
996 if (!list_empty(&family
->faces
))
997 return &family
->faces
;
999 return family
->replacement
;
1002 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
1008 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
1010 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1012 const struct list
*face_list
;
1013 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
1015 face_list
= get_face_list_from_family(family
);
1016 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
1020 file
= strrchrW(face
->file
, '/');
1025 if(strcmpiW(file
, file_name
)) continue;
1033 static Family
*find_family_from_name(const WCHAR
*name
)
1037 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1039 if(!strcmpiW(family
->FamilyName
, name
))
1046 static Family
*find_family_from_any_name(const WCHAR
*name
)
1050 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1052 if(!strcmpiW(family
->FamilyName
, name
))
1054 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1061 static void DumpSubstList(void)
1065 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1067 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1068 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1069 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1071 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1072 debugstr_w(psub
->to
.name
));
1076 static LPWSTR
strdupW(LPCWSTR p
)
1079 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1080 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1081 memcpy(ret
, p
, len
);
1085 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1090 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1092 if(!strcmpiW(element
->from
.name
, from_name
) &&
1093 (element
->from
.charset
== from_charset
||
1094 element
->from
.charset
== -1))
1101 #define ADD_FONT_SUBST_FORCE 1
1103 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1105 FontSubst
*from_exist
, *to_exist
;
1107 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1109 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1111 list_remove(&from_exist
->entry
);
1112 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1113 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1114 HeapFree(GetProcessHeap(), 0, from_exist
);
1120 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1124 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1125 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1128 list_add_tail(subst_list
, &subst
->entry
);
1133 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1134 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1135 HeapFree(GetProcessHeap(), 0, subst
);
1139 static WCHAR
*towstr(UINT cp
, const char *str
)
1144 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1145 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1146 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1150 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1152 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1153 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1154 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1158 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1160 CHAR
*p
= strrchr(str
, ',');
1164 nc
->charset
= strtol(p
+1, NULL
, 10);
1167 nc
->name
= towstr(CP_ACP
, str
);
1170 static void LoadSubstList(void)
1174 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1178 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1179 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1180 &hkey
) == ERROR_SUCCESS
) {
1182 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1183 &valuelen
, &datalen
, NULL
, NULL
);
1185 valuelen
++; /* returned value doesn't include room for '\0' */
1186 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1187 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1191 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1192 &dlen
) == ERROR_SUCCESS
) {
1193 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1195 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1196 split_subst_info(&psub
->from
, value
);
1197 split_subst_info(&psub
->to
, data
);
1199 /* Win 2000 doesn't allow mapping between different charsets
1200 or mapping of DEFAULT_CHARSET */
1201 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1202 psub
->to
.charset
== DEFAULT_CHARSET
) {
1203 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1204 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1205 HeapFree(GetProcessHeap(), 0, psub
);
1207 add_font_subst(&font_subst_list
, psub
, 0);
1209 /* reset dlen and vlen */
1213 HeapFree(GetProcessHeap(), 0, data
);
1214 HeapFree(GetProcessHeap(), 0, value
);
1220 static const LANGID mac_langid_table
[] =
1222 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
1223 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
1224 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
1225 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
1226 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
1227 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
1228 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
1229 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
1230 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
1231 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
1232 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
1233 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
1234 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
1235 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
1236 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
1237 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
1238 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
1239 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
1240 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
1241 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1242 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
1243 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
1244 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
1245 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
1246 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
1247 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
1248 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
1249 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
1250 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
1251 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
1252 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
1253 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
1254 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
1255 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1256 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
1257 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
1258 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
1259 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
1260 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
1261 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
1262 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
1263 0, /* TT_MAC_LANGID_YIDDISH */
1264 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
1265 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
1266 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
1267 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
1268 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
1269 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
1270 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
1271 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
1272 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1273 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
1274 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
1275 0, /* TT_MAC_LANGID_MOLDAVIAN */
1276 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
1277 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
1278 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
1279 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
1280 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1281 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
1282 0, /* TT_MAC_LANGID_KURDISH */
1283 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
1284 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
1285 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
1286 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
1287 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
1288 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
1289 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
1290 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
1291 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
1292 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
1293 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
1294 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
1295 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
1296 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
1297 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
1298 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
1299 0, /* TT_MAC_LANGID_BURMESE */
1300 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
1301 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
1302 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
1303 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
1304 0, /* TT_MAC_LANGID_TAGALOG */
1305 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1306 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1307 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
1308 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
1309 0, /* TT_MAC_LANGID_GALLA */
1310 0, /* TT_MAC_LANGID_SOMALI */
1311 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
1312 0, /* TT_MAC_LANGID_RUANDA */
1313 0, /* TT_MAC_LANGID_RUNDI */
1314 0, /* TT_MAC_LANGID_CHEWA */
1315 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
1316 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
1317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1319 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
1320 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
1321 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
1322 0, /* TT_MAC_LANGID_LATIN */
1323 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
1324 0, /* TT_MAC_LANGID_GUARANI */
1325 0, /* TT_MAC_LANGID_AYMARA */
1326 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
1327 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
1328 0, /* TT_MAC_LANGID_DZONGKHA */
1329 0, /* TT_MAC_LANGID_JAVANESE */
1330 0, /* TT_MAC_LANGID_SUNDANESE */
1331 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
1332 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
1333 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
1334 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
1335 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1336 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
1337 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
1338 0, /* TT_MAC_LANGID_TONGAN */
1339 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1340 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
1341 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1344 static inline WORD
get_mac_code_page( const FT_SfntName
*name
)
1346 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
1347 return 10000 + name
->encoding_id
;
1350 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
1355 switch (name
->platform_id
)
1357 case TT_PLATFORM_MICROSOFT
:
1358 res
+= 5; /* prefer the Microsoft name */
1359 switch (name
->encoding_id
)
1361 case TT_MS_ID_UNICODE_CS
:
1362 case TT_MS_ID_SYMBOL_CS
:
1363 name_lang
= name
->language_id
;
1369 case TT_PLATFORM_MACINTOSH
:
1370 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
1371 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1372 name_lang
= mac_langid_table
[name
->language_id
];
1374 case TT_PLATFORM_APPLE_UNICODE
:
1375 res
+= 2; /* prefer Unicode encodings */
1376 switch (name
->encoding_id
)
1378 case TT_APPLE_ID_DEFAULT
:
1379 case TT_APPLE_ID_ISO_10646
:
1380 case TT_APPLE_ID_UNICODE_2_0
:
1381 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1382 name_lang
= mac_langid_table
[name
->language_id
];
1391 if (name_lang
== lang
) res
+= 30;
1392 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
1393 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
1397 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
1403 switch (name
->platform_id
)
1405 case TT_PLATFORM_APPLE_UNICODE
:
1406 case TT_PLATFORM_MICROSOFT
:
1407 ret
= HeapAlloc( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
1408 for (i
= 0; i
< name
->string_len
/ 2; i
++)
1409 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
1412 case TT_PLATFORM_MACINTOSH
:
1413 codepage
= get_mac_code_page( name
);
1414 i
= MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, NULL
, 0 );
1415 ret
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(WCHAR
) );
1416 MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, ret
, i
);
1423 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
1426 FT_UInt num_names
, name_index
;
1427 int res
, best_lang
= 0, best_index
= -1;
1429 if (!FT_IS_SFNT(ft_face
)) return NULL
;
1431 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
1433 for (name_index
= 0; name_index
< num_names
; name_index
++)
1435 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
1436 if (name
.name_id
!= name_id
) continue;
1437 res
= match_name_table_language( &name
, language_id
);
1438 if (res
> best_lang
)
1441 best_index
= name_index
;
1445 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
1447 WCHAR
*ret
= copy_name_table_string( &name
);
1448 TRACE( "name %u found platform %u lang %04x %s\n",
1449 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
1455 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1457 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1458 if (f1
->scalable
) return TRUE
;
1459 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1460 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1463 static void release_family( Family
*family
)
1465 if (--family
->refcount
) return;
1466 assert( list_empty( &family
->faces
));
1467 list_remove( &family
->entry
);
1468 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1469 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1470 HeapFree( GetProcessHeap(), 0, family
);
1473 static void release_face( Face
*face
)
1475 if (--face
->refcount
) return;
1478 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1479 list_remove( &face
->entry
);
1480 release_family( face
->family
);
1482 HeapFree( GetProcessHeap(), 0, face
->file
);
1483 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1484 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1485 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1486 HeapFree( GetProcessHeap(), 0, face
);
1489 static inline int style_order(const Face
*face
)
1491 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1499 case NTM_BOLD
| NTM_ITALIC
:
1502 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1503 debugstr_w(face
->family
->FamilyName
),
1504 debugstr_w(face
->StyleName
),
1510 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1514 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1516 if (faces_equal( face
, cursor
))
1518 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1519 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1520 cursor
->font_version
, face
->font_version
);
1522 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1525 TRACE("Font %s already in list, refcount now %d\n",
1526 debugstr_w(face
->file
), cursor
->refcount
);
1529 if (face
->font_version
<= cursor
->font_version
)
1531 TRACE("Original font %s is newer so skipping %s\n",
1532 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1537 TRACE("Replacing original %s with %s\n",
1538 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1539 list_add_before( &cursor
->entry
, &face
->entry
);
1540 face
->family
= family
;
1543 release_face( cursor
);
1548 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1550 if (style_order( face
) < style_order( cursor
)) break;
1553 list_add_before( &cursor
->entry
, &face
->entry
);
1554 face
->family
= family
;
1560 /****************************************************************
1561 * NB This function stores the ptrs to the strings to save copying.
1562 * Don't free them after calling.
1564 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1566 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1567 family
->refcount
= 1;
1568 family
->FamilyName
= name
;
1569 family
->EnglishName
= english_name
;
1570 list_init( &family
->faces
);
1571 family
->replacement
= &family
->faces
;
1572 list_add_tail( &font_list
, &family
->entry
);
1577 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1579 DWORD type
, size
= sizeof(DWORD
);
1581 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1582 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1585 return ERROR_BAD_CONFIGURATION
;
1587 return ERROR_SUCCESS
;
1590 static inline LONG
reg_load_ftlong(HKEY hkey
, const WCHAR
*value
, FT_Long
*data
)
1593 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1598 static inline LONG
reg_load_ftshort(HKEY hkey
, const WCHAR
*value
, FT_Short
*data
)
1601 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1606 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1608 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1611 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1613 DWORD needed
, strike_index
= 0;
1616 /* If we have a File Name key then this is a real font, not just the parent
1617 key of a bunch of non-scalable strikes */
1618 needed
= buffer_size
;
1619 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1622 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1623 face
->cached_enum_data
= NULL
;
1624 face
->family
= NULL
;
1627 face
->file
= strdupW( buffer
);
1628 face
->StyleName
= strdupW(face_name
);
1630 needed
= buffer_size
;
1631 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1632 face
->FullName
= strdupW( buffer
);
1634 face
->FullName
= NULL
;
1636 reg_load_ftlong(hkey_face
, face_index_value
, &face
->face_index
);
1637 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1638 reg_load_ftlong(hkey_face
, face_version_value
, &face
->font_version
);
1639 reg_load_dword(hkey_face
, face_flags_value
, &face
->flags
);
1641 needed
= sizeof(face
->fs
);
1642 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1644 if(reg_load_ftshort(hkey_face
, face_height_value
, &face
->size
.height
) != ERROR_SUCCESS
)
1646 face
->scalable
= TRUE
;
1647 memset(&face
->size
, 0, sizeof(face
->size
));
1651 face
->scalable
= FALSE
;
1652 reg_load_ftshort(hkey_face
, face_width_value
, &face
->size
.width
);
1653 reg_load_ftlong(hkey_face
, face_size_value
, &face
->size
.size
);
1654 reg_load_ftlong(hkey_face
, face_x_ppem_value
, &face
->size
.x_ppem
);
1655 reg_load_ftlong(hkey_face
, face_y_ppem_value
, &face
->size
.y_ppem
);
1656 reg_load_ftshort(hkey_face
, face_internal_leading_value
, &face
->size
.internal_leading
);
1658 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1659 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1660 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1663 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1664 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1665 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1666 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1668 if (insert_face_in_family_list(face
, family
))
1669 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1671 release_face( face
);
1674 /* load bitmap strikes */
1676 needed
= buffer_size
;
1677 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1679 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1681 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1682 RegCloseKey(hkey_strike
);
1684 needed
= buffer_size
;
1688 /* move vertical fonts after their horizontal counterpart */
1689 /* assumes that font_list is already sorted by family name */
1690 static void reorder_vertical_fonts(void)
1692 Family
*family
, *next
, *vert_family
;
1693 struct list
*ptr
, *vptr
;
1694 struct list vertical_families
= LIST_INIT( vertical_families
);
1696 LIST_FOR_EACH_ENTRY_SAFE( family
, next
, &font_list
, Family
, entry
)
1698 if (family
->FamilyName
[0] != '@') continue;
1699 list_remove( &family
->entry
);
1700 list_add_tail( &vertical_families
, &family
->entry
);
1703 ptr
= list_head( &font_list
);
1704 vptr
= list_head( &vertical_families
);
1707 family
= LIST_ENTRY( ptr
, Family
, entry
);
1708 vert_family
= LIST_ENTRY( vptr
, Family
, entry
);
1709 if (strcmpiW( family
->FamilyName
, vert_family
->FamilyName
+ 1 ) > 0)
1711 list_remove( vptr
);
1712 list_add_before( ptr
, vptr
);
1713 vptr
= list_head( &vertical_families
);
1715 else ptr
= list_next( &font_list
, ptr
);
1717 list_move_tail( &font_list
, &vertical_families
);
1720 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1722 DWORD size
, family_index
= 0;
1727 size
= sizeof(buffer
);
1728 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1730 WCHAR
*english_family
= NULL
;
1731 WCHAR
*family_name
= strdupW( buffer
);
1732 DWORD face_index
= 0;
1734 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1735 TRACE("opened family key %s\n", debugstr_w(family_name
));
1736 size
= sizeof(buffer
);
1737 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1738 english_family
= strdupW( buffer
);
1740 family
= create_family(family_name
, english_family
);
1744 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1745 subst
->from
.name
= strdupW(english_family
);
1746 subst
->from
.charset
= -1;
1747 subst
->to
.name
= strdupW(family_name
);
1748 subst
->to
.charset
= -1;
1749 add_font_subst(&font_subst_list
, subst
, 0);
1752 size
= sizeof(buffer
);
1753 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1755 WCHAR
*face_name
= strdupW( buffer
);
1758 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1760 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1761 RegCloseKey(hkey_face
);
1763 HeapFree( GetProcessHeap(), 0, face_name
);
1764 size
= sizeof(buffer
);
1766 RegCloseKey(hkey_family
);
1767 release_family( family
);
1768 size
= sizeof(buffer
);
1771 reorder_vertical_fonts();
1774 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1777 HKEY hkey_wine_fonts
;
1779 /* We don't want to create the fonts key as volatile, so open this first */
1780 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1781 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1782 if(ret
!= ERROR_SUCCESS
)
1784 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1788 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1789 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1790 RegCloseKey(hkey_wine_fonts
);
1794 static void add_face_to_cache(Face
*face
)
1796 HKEY hkey_family
, hkey_face
;
1797 WCHAR
*face_key_name
;
1799 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1800 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1801 if(face
->family
->EnglishName
)
1802 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1803 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1806 face_key_name
= face
->StyleName
;
1809 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1810 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1811 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1813 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1816 HeapFree(GetProcessHeap(), 0, face_key_name
);
1818 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1819 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1821 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1822 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1824 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1825 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1826 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1827 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1829 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1833 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1834 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1835 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1836 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1837 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1838 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1840 RegCloseKey(hkey_face
);
1841 RegCloseKey(hkey_family
);
1844 static void remove_face_from_cache( Face
*face
)
1848 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1852 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1856 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1857 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1858 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1859 RegDeleteKeyW( hkey_family
, face_key_name
);
1860 HeapFree(GetProcessHeap(), 0, face_key_name
);
1862 RegCloseKey(hkey_family
);
1865 static WCHAR
*prepend_at(WCHAR
*family
)
1872 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1874 strcpyW(str
+ 1, family
);
1875 HeapFree(GetProcessHeap(), 0, family
);
1879 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1881 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
) );
1882 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1884 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1890 else if (!strcmpiW( *name
, *english
))
1892 HeapFree( GetProcessHeap(), 0, *english
);
1898 *name
= prepend_at( *name
);
1899 *english
= prepend_at( *english
);
1903 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1906 WCHAR
*name
, *english_name
;
1908 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1910 family
= find_family_from_name( name
);
1914 family
= create_family( name
, english_name
);
1917 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1918 subst
->from
.name
= strdupW( english_name
);
1919 subst
->from
.charset
= -1;
1920 subst
->to
.name
= strdupW( name
);
1921 subst
->to
.charset
= -1;
1922 add_font_subst( &font_subst_list
, subst
, 0 );
1927 HeapFree( GetProcessHeap(), 0, name
);
1928 HeapFree( GetProcessHeap(), 0, english_name
);
1935 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1937 FT_Fixed version
= 0;
1940 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1941 if (header
) version
= header
->Font_Revision
;
1946 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1949 FT_ULong table_size
= 0;
1950 FT_WinFNT_HeaderRec winfnt_header
;
1952 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1953 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1955 /* fixup the flag for our fake-bold implementation. */
1956 if (!FT_IS_SCALABLE( ft_face
) &&
1957 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
1958 winfnt_header
.weight
> FW_NORMAL
)
1961 if (flags
== 0) flags
= NTM_REGULAR
;
1963 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1964 flags
|= NTM_PS_OPENTYPE
;
1969 static inline void get_bitmap_size( FT_Face ft_face
, Bitmap_Size
*face_size
)
1971 My_FT_Bitmap_Size
*size
;
1972 FT_WinFNT_HeaderRec winfnt_header
;
1974 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1975 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1976 size
->height
, size
->width
, size
->size
>> 6,
1977 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1978 face_size
->height
= size
->height
;
1979 face_size
->width
= size
->width
;
1980 face_size
->size
= size
->size
;
1981 face_size
->x_ppem
= size
->x_ppem
;
1982 face_size
->y_ppem
= size
->y_ppem
;
1984 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
1985 face_size
->internal_leading
= winfnt_header
.internal_leading
;
1986 if (winfnt_header
.external_leading
> 0 &&
1987 (face_size
->height
==
1988 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
1989 face_size
->height
= winfnt_header
.pixel_height
;
1993 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1998 FT_WinFNT_HeaderRec winfnt_header
;
2001 memset( fs
, 0, sizeof(*fs
) );
2003 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
2006 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
2007 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
2008 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
2009 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
2011 if (os2
->version
== 0)
2013 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
2014 fs
->fsCsb
[0] = FS_LATIN1
;
2016 fs
->fsCsb
[0] = FS_SYMBOL
;
2020 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
2021 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
2026 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
2028 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
2029 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
2030 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
2035 if (fs
->fsCsb
[0] == 0)
2037 /* let's see if we can find any interesting cmaps */
2038 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2040 switch (ft_face
->charmaps
[i
]->encoding
)
2042 case FT_ENCODING_UNICODE
:
2043 case FT_ENCODING_APPLE_ROMAN
:
2044 fs
->fsCsb
[0] |= FS_LATIN1
;
2046 case FT_ENCODING_MS_SYMBOL
:
2047 fs
->fsCsb
[0] |= FS_SYMBOL
;
2056 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2060 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
2063 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
2064 if (!face
->StyleName
) face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
2066 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
2067 if (flags
& ADDFONT_VERTICAL_FONT
)
2068 face
->FullName
= prepend_at( face
->FullName
);
2074 face
->file
= towstr( CP_UNIXCP
, file
);
2075 face
->font_data_ptr
= NULL
;
2076 face
->font_data_size
= 0;
2077 if (!stat( file
, &st
))
2079 face
->dev
= st
.st_dev
;
2080 face
->ino
= st
.st_ino
;
2086 face
->font_data_ptr
= font_data_ptr
;
2087 face
->font_data_size
= font_data_size
;
2090 face
->face_index
= face_index
;
2091 get_fontsig( ft_face
, &face
->fs
);
2092 face
->ntmFlags
= get_ntm_flags( ft_face
);
2093 face
->font_version
= get_font_version( ft_face
);
2095 if (FT_IS_SCALABLE( ft_face
))
2097 memset( &face
->size
, 0, sizeof(face
->size
) );
2098 face
->scalable
= TRUE
;
2102 get_bitmap_size( ft_face
, &face
->size
);
2103 face
->scalable
= FALSE
;
2106 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
2107 face
->flags
= flags
;
2108 face
->family
= NULL
;
2109 face
->cached_enum_data
= NULL
;
2111 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2112 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
2113 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
2114 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
2119 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2120 FT_Long face_index
, DWORD flags
)
2125 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
2126 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
2127 if (strlenW(family
->FamilyName
) >= LF_FACESIZE
)
2129 WARN("Ignoring %s because name is too long\n", debugstr_w(family
->FamilyName
));
2130 release_face( face
);
2131 release_family( family
);
2135 if (insert_face_in_family_list( face
, family
))
2137 if (flags
& ADDFONT_ADD_TO_CACHE
)
2138 add_face_to_cache( face
);
2140 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
2141 debugstr_w(face
->StyleName
));
2143 release_face( face
);
2144 release_family( family
);
2147 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2148 FT_Long face_index
, BOOL allow_bitmap
)
2156 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
2157 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
2161 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
2162 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
2167 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
2171 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2172 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
2174 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2178 if (!FT_IS_SFNT( ft_face
))
2180 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
2182 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2188 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
2189 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
2190 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
2192 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2193 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
2197 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2198 we don't want to load these. */
2199 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
2203 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
2205 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
2211 if (!ft_face
->family_name
|| !ft_face
->style_name
)
2213 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
2219 pFT_Done_Face( ft_face
);
2223 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
2226 FT_Long face_index
= 0, num_faces
;
2229 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2230 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
2232 #ifdef HAVE_CARBON_CARBON_H
2235 char **mac_list
= expand_mac_font(file
);
2238 BOOL had_one
= FALSE
;
2240 for(cursor
= mac_list
; *cursor
; cursor
++)
2243 AddFontToList(*cursor
, NULL
, 0, flags
);
2244 HeapFree(GetProcessHeap(), 0, *cursor
);
2246 HeapFree(GetProcessHeap(), 0, mac_list
);
2251 #endif /* HAVE_CARBON_CARBON_H */
2254 const DWORD FS_DBCS_MASK
= FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
;
2257 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
2258 if (!ft_face
) return 0;
2260 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
2262 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
2263 pFT_Done_Face(ft_face
);
2267 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
2270 get_fontsig(ft_face
, &fs
);
2271 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
2273 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
2274 flags
| ADDFONT_VERTICAL_FONT
);
2278 num_faces
= ft_face
->num_faces
;
2279 pFT_Done_Face(ft_face
);
2280 } while(num_faces
> ++face_index
);
2284 static int remove_font_resource( const char *file
, DWORD flags
)
2286 Family
*family
, *family_next
;
2287 Face
*face
, *face_next
;
2291 if (stat( file
, &st
) == -1) return 0;
2292 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2295 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2297 if (!face
->file
) continue;
2298 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2299 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2301 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2302 release_face( face
);
2306 release_family( family
);
2311 static void DumpFontList(void)
2316 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2317 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2318 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2319 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2321 TRACE(" %d", face
->size
.height
);
2327 static BOOL
map_font_family(const WCHAR
*orig
, const WCHAR
*repl
)
2329 Family
*family
= find_family_from_any_name(repl
);
2332 Family
*new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2333 if (new_family
!= NULL
)
2335 TRACE("mapping %s to %s\n", debugstr_w(repl
), debugstr_w(orig
));
2336 new_family
->FamilyName
= strdupW(orig
);
2337 new_family
->EnglishName
= NULL
;
2338 list_init(&new_family
->faces
);
2339 new_family
->replacement
= &family
->faces
;
2340 list_add_tail(&font_list
, &new_family
->entry
);
2344 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl
));
2348 /***********************************************************
2349 * The replacement list is a way to map an entire font
2350 * family onto another family. For example adding
2352 * [HKCU\Software\Wine\Fonts\Replacements]
2353 * "Wingdings"="Winedings"
2355 * would enumerate the Winedings font both as Winedings and
2356 * Wingdings. However if a real Wingdings font is present the
2357 * replacement does not take place.
2360 static void LoadReplaceList(void)
2363 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2367 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2368 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2370 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2371 &valuelen
, &datalen
, NULL
, NULL
);
2373 valuelen
++; /* returned value doesn't include room for '\0' */
2374 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2375 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2379 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
, &dlen
) == ERROR_SUCCESS
)
2381 /* "NewName"="Oldname" */
2382 if(!find_family_from_any_name(value
))
2384 if (type
== REG_MULTI_SZ
)
2386 WCHAR
*replace
= data
;
2389 if (map_font_family(value
, replace
))
2391 replace
+= strlenW(replace
) + 1;
2394 else if (type
== REG_SZ
)
2395 map_font_family(value
, data
);
2398 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2400 /* reset dlen and vlen */
2404 HeapFree(GetProcessHeap(), 0, data
);
2405 HeapFree(GetProcessHeap(), 0, value
);
2410 static const WCHAR
*font_links_list
[] =
2412 Lucida_Sans_Unicode
,
2413 Microsoft_Sans_Serif
,
2417 static const struct font_links_defaults_list
2419 /* Keyed off substitution for "MS Shell Dlg" */
2420 const WCHAR
*shelldlg
;
2421 /* Maximum of four substitutes, plus terminating NULL pointer */
2422 const WCHAR
*substitutes
[5];
2423 } font_links_defaults_list
[] =
2425 /* Non East-Asian */
2426 { Tahoma
, /* FIXME unverified ordering */
2427 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2429 /* Below lists are courtesy of
2430 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2434 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2436 /* Chinese Simplified */
2438 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2442 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2444 /* Chinese Traditional */
2446 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2451 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2453 SYSTEM_LINKS
*font_link
;
2455 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2457 if(!strcmpiW(font_link
->font_name
, name
))
2464 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2475 SYSTEM_LINKS
*font_link
;
2477 psub
= get_font_subst(&font_subst_list
, name
, -1);
2478 /* Don't store fonts that are only substitutes for other fonts */
2481 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2485 font_link
= find_font_link(name
);
2486 if (font_link
== NULL
)
2488 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2489 font_link
->font_name
= strdupW(name
);
2490 list_init(&font_link
->links
);
2491 list_add_tail(&system_links
, &font_link
->entry
);
2494 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2495 for (i
= 0; values
[i
] != NULL
; i
++)
2497 const struct list
*face_list
;
2498 CHILD_FONT
*child_font
;
2501 if (!strcmpiW(name
,value
))
2503 psub
= get_font_subst(&font_subst_list
, value
, -1);
2505 value
= psub
->to
.name
;
2506 family
= find_family_from_name(value
);
2510 /* Use first extant filename for this Family */
2511 face_list
= get_face_list_from_family(family
);
2512 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2516 file
= strrchrW(face
->file
, '/');
2525 face
= find_face_from_filename(file
, value
);
2528 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2532 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2533 child_font
->face
= face
;
2534 child_font
->font
= NULL
;
2535 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2536 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2537 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2538 child_font
->face
->face_index
);
2539 list_add_tail(&font_link
->links
, &child_font
->entry
);
2541 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2547 /*************************************************************
2550 static BOOL
init_system_links(void)
2554 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2555 WCHAR
*value
, *data
;
2556 WCHAR
*entry
, *next
;
2557 SYSTEM_LINKS
*font_link
, *system_font_link
;
2558 CHILD_FONT
*child_font
;
2559 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2560 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2561 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2566 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2568 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2569 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2570 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2571 val_len
= max_val
+ 1;
2572 data_len
= max_data
;
2574 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2576 psub
= get_font_subst(&font_subst_list
, value
, -1);
2577 /* Don't store fonts that are only substitutes for other fonts */
2580 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2583 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2584 font_link
->font_name
= strdupW(value
);
2585 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2586 list_init(&font_link
->links
);
2587 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2590 CHILD_FONT
*child_font
;
2592 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2594 next
= entry
+ strlenW(entry
) + 1;
2596 face_name
= strchrW(entry
, ',');
2600 while(isspaceW(*face_name
))
2603 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2605 face_name
= psub
->to
.name
;
2607 face
= find_face_from_filename(entry
, face_name
);
2610 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2614 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2615 child_font
->face
= face
;
2616 child_font
->font
= NULL
;
2617 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2618 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2619 TRACE("Adding file %s index %ld\n",
2620 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2621 list_add_tail(&font_link
->links
, &child_font
->entry
);
2623 list_add_tail(&system_links
, &font_link
->entry
);
2625 val_len
= max_val
+ 1;
2626 data_len
= max_data
;
2629 HeapFree(GetProcessHeap(), 0, value
);
2630 HeapFree(GetProcessHeap(), 0, data
);
2635 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2637 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2641 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2643 const FontSubst
*psub2
;
2644 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2646 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2648 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2649 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2651 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2652 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2654 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2656 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2662 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2665 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2666 system_font_link
->font_name
= strdupW(System
);
2667 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2668 list_init(&system_font_link
->links
);
2670 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2673 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2674 child_font
->face
= face
;
2675 child_font
->font
= NULL
;
2676 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2677 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2678 TRACE("Found Tahoma in %s index %ld\n",
2679 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2680 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2682 font_link
= find_font_link(Tahoma
);
2683 if (font_link
!= NULL
)
2685 CHILD_FONT
*font_link_entry
;
2686 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2688 CHILD_FONT
*new_child
;
2689 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2690 new_child
->face
= font_link_entry
->face
;
2691 new_child
->font
= NULL
;
2692 new_child
->face
->refcount
++;
2693 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2694 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2695 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2698 list_add_tail(&system_links
, &system_font_link
->entry
);
2702 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2705 struct dirent
*dent
;
2706 char path
[MAX_PATH
];
2708 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2710 dir
= opendir(dirname
);
2712 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2715 while((dent
= readdir(dir
)) != NULL
) {
2716 struct stat statbuf
;
2718 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2721 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2723 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2725 if(stat(path
, &statbuf
) == -1)
2727 WARN("Can't stat %s\n", debugstr_a(path
));
2730 if(S_ISDIR(statbuf
.st_mode
))
2731 ReadFontDir(path
, external_fonts
);
2734 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2735 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2736 AddFontToList(path
, NULL
, 0, addfont_flags
);
2743 #ifdef SONAME_LIBFONTCONFIG
2745 static BOOL fontconfig_enabled
;
2747 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2753 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2754 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2756 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2760 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2761 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2762 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2763 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2764 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2770 static void init_fontconfig(void)
2772 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2776 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2780 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2781 LOAD_FUNCPTR(FcConfigSubstitute
);
2782 LOAD_FUNCPTR(FcFontList
);
2783 LOAD_FUNCPTR(FcFontSetDestroy
);
2784 LOAD_FUNCPTR(FcInit
);
2785 LOAD_FUNCPTR(FcObjectSetAdd
);
2786 LOAD_FUNCPTR(FcObjectSetCreate
);
2787 LOAD_FUNCPTR(FcObjectSetDestroy
);
2788 LOAD_FUNCPTR(FcPatternCreate
);
2789 LOAD_FUNCPTR(FcPatternDestroy
);
2790 LOAD_FUNCPTR(FcPatternGetBool
);
2791 LOAD_FUNCPTR(FcPatternGetInteger
);
2792 LOAD_FUNCPTR(FcPatternGetString
);
2797 FcPattern
*pattern
= pFcPatternCreate();
2798 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2799 default_aa_flags
= parse_aa_pattern( pattern
);
2800 pFcPatternDestroy( pattern
);
2801 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2802 fontconfig_enabled
= TRUE
;
2806 static void load_fontconfig_fonts(void)
2815 if (!fontconfig_enabled
) return;
2817 pat
= pFcPatternCreate();
2818 os
= pFcObjectSetCreate();
2819 pFcObjectSetAdd(os
, FC_FILE
);
2820 pFcObjectSetAdd(os
, FC_SCALABLE
);
2821 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2822 pFcObjectSetAdd(os
, FC_RGBA
);
2823 fontset
= pFcFontList(NULL
, pat
, os
);
2824 if(!fontset
) return;
2825 for(i
= 0; i
< fontset
->nfont
; i
++) {
2829 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2832 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2834 /* We're just interested in OT/TT fonts for now, so this hack just
2835 picks up the scalable fonts without extensions .pf[ab] to save time
2836 loading every other font */
2838 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2840 TRACE("not scalable\n");
2844 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2845 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2847 len
= strlen( file
);
2848 if(len
< 4) continue;
2849 ext
= &file
[ len
- 3 ];
2850 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2851 AddFontToList(file
, NULL
, 0,
2852 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2854 pFcFontSetDestroy(fontset
);
2855 pFcObjectSetDestroy(os
);
2856 pFcPatternDestroy(pat
);
2859 #elif defined(HAVE_CARBON_CARBON_H)
2861 static void load_mac_font_callback(const void *value
, void *context
)
2863 CFStringRef pathStr
= value
;
2867 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2868 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2869 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2871 TRACE("font file %s\n", path
);
2872 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2874 HeapFree(GetProcessHeap(), 0, path
);
2877 static void load_mac_fonts(void)
2879 CFStringRef removeDupesKey
;
2880 CFBooleanRef removeDupesValue
;
2881 CFDictionaryRef options
;
2882 CTFontCollectionRef col
;
2884 CFMutableSetRef paths
;
2887 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2888 removeDupesValue
= kCFBooleanTrue
;
2889 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2890 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2891 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2892 if (options
) CFRelease(options
);
2895 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2899 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2903 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2907 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2910 WARN("CFSetCreateMutable failed\n");
2915 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2917 CTFontDescriptorRef desc
;
2926 desc
= CFArrayGetValueAtIndex(descs
, i
);
2928 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2929 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2930 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2931 if (!font
) continue;
2933 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2940 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2942 if (status
!= noErr
) continue;
2944 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2947 ext
= CFURLCopyPathExtension(url
);
2950 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2951 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2960 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2962 if (!path
) continue;
2964 CFSetAddValue(paths
, path
);
2970 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2976 static char *get_font_dir(void)
2978 const char *build_dir
, *data_dir
;
2981 if ((data_dir
= wine_get_data_dir()))
2983 if (!(name
= HeapAlloc( GetProcessHeap(), 0, strlen(data_dir
) + 1 + sizeof(WINE_FONT_DIR
) )))
2985 strcpy( name
, data_dir
);
2986 strcat( name
, "/" );
2987 strcat( name
, WINE_FONT_DIR
);
2989 else if ((build_dir
= wine_get_build_dir()))
2991 if (!(name
= HeapAlloc( GetProcessHeap(), 0, strlen(build_dir
) + sizeof("/fonts") )))
2993 strcpy( name
, build_dir
);
2994 strcat( name
, "/fonts" );
2999 static char *get_data_dir_path( LPCWSTR file
)
3001 char *unix_name
= NULL
;
3002 char *font_dir
= get_font_dir();
3006 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
3008 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(font_dir
) + len
+ 1 );
3009 strcpy(unix_name
, font_dir
);
3010 strcat(unix_name
, "/");
3012 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
3013 HeapFree( GetProcessHeap(), 0, font_dir
);
3018 static BOOL
load_font_from_data_dir(LPCWSTR file
)
3021 char *unix_name
= get_data_dir_path( file
);
3025 EnterCriticalSection( &freetype_cs
);
3026 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3027 LeaveCriticalSection( &freetype_cs
);
3028 HeapFree(GetProcessHeap(), 0, unix_name
);
3033 static char *get_winfonts_dir_path(LPCWSTR file
)
3035 static const WCHAR slashW
[] = {'\\','\0'};
3036 WCHAR windowsdir
[MAX_PATH
];
3038 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3039 strcatW(windowsdir
, fontsW
);
3040 strcatW(windowsdir
, slashW
);
3041 strcatW(windowsdir
, file
);
3042 return wine_get_unix_file_name( windowsdir
);
3045 static void load_system_fonts(void)
3048 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
3049 const WCHAR
* const *value
;
3051 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3054 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3055 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3056 strcatW(windowsdir
, fontsW
);
3057 for(value
= SystemFontValues
; *value
; value
++) {
3058 dlen
= sizeof(data
);
3059 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
3063 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3064 if((unixname
= wine_get_unix_file_name(pathW
))) {
3065 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3066 HeapFree(GetProcessHeap(), 0, unixname
);
3069 load_font_from_data_dir(data
);
3076 /*************************************************************
3078 * This adds registry entries for any externally loaded fonts
3079 * (fonts from fontconfig or FontDirs). It also deletes entries
3080 * of no longer existing fonts.
3083 static void update_reg_entries(void)
3085 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3091 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3093 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3094 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3095 ERR("Can't create Windows font reg key\n");
3099 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3100 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3101 ERR("Can't create Windows font reg key\n");
3105 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
3106 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
3107 ERR("Can't create external font reg key\n");
3111 /* enumerate the fonts and add external ones to the two keys */
3113 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
3114 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
3116 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
3120 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3121 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3122 strcpyW(valueW
, face
->FullName
);
3126 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3127 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3128 strcpyW(valueW
, family
->FamilyName
);
3131 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
3132 path
= wine_get_dos_file_name( buffer
);
3133 HeapFree( GetProcessHeap(), 0, buffer
);
3137 else if ((file
= strrchrW(face
->file
, '/')))
3142 len
= strlenW(file
) + 1;
3143 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3144 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3145 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3147 HeapFree(GetProcessHeap(), 0, path
);
3148 HeapFree(GetProcessHeap(), 0, valueW
);
3152 if(external_key
) RegCloseKey(external_key
);
3153 if(win9x_key
) RegCloseKey(win9x_key
);
3154 if(winnt_key
) RegCloseKey(winnt_key
);
3157 static void delete_external_font_keys(void)
3159 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3160 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
3164 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3165 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3166 ERR("Can't create Windows font reg key\n");
3170 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3171 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3172 ERR("Can't create Windows font reg key\n");
3176 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
3177 ERR("Can't create external font reg key\n");
3181 /* Delete all external fonts added last time */
3183 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3184 &valuelen
, &datalen
, NULL
, NULL
);
3185 valuelen
++; /* returned value doesn't include room for '\0' */
3186 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3187 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3189 dlen
= datalen
* sizeof(WCHAR
);
3192 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
3193 &dlen
) == ERROR_SUCCESS
) {
3195 RegDeleteValueW(winnt_key
, valueW
);
3196 RegDeleteValueW(win9x_key
, valueW
);
3197 /* reset dlen and vlen */
3201 HeapFree(GetProcessHeap(), 0, data
);
3202 HeapFree(GetProcessHeap(), 0, valueW
);
3204 /* Delete the old external fonts key */
3205 RegCloseKey(external_key
);
3206 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
3209 if(win9x_key
) RegCloseKey(win9x_key
);
3210 if(winnt_key
) RegCloseKey(winnt_key
);
3213 /*************************************************************
3214 * WineEngAddFontResourceEx
3217 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3223 if (ft_handle
) /* do it only if we have freetype up and running */
3227 EnterCriticalSection( &freetype_cs
);
3229 if((unixname
= wine_get_unix_file_name(file
)))
3231 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3233 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3234 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
3235 HeapFree(GetProcessHeap(), 0, unixname
);
3237 if (!ret
&& !strchrW(file
, '\\')) {
3238 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3239 if ((unixname
= get_winfonts_dir_path( file
)))
3241 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3242 HeapFree(GetProcessHeap(), 0, unixname
);
3244 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3245 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3247 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3248 HeapFree(GetProcessHeap(), 0, unixname
);
3252 LeaveCriticalSection( &freetype_cs
);
3257 /*************************************************************
3258 * WineEngAddFontMemResourceEx
3261 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3265 if (ft_handle
) /* do it only if we have freetype up and running */
3267 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
3269 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
3270 memcpy(pFontCopy
, pbFont
, cbFont
);
3272 EnterCriticalSection( &freetype_cs
);
3273 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3274 LeaveCriticalSection( &freetype_cs
);
3278 TRACE("AddFontToList failed\n");
3279 HeapFree(GetProcessHeap(), 0, pFontCopy
);
3282 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3283 * For now return something unique but quite random
3285 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
3286 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
3293 /*************************************************************
3294 * WineEngRemoveFontResourceEx
3297 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3303 if (ft_handle
) /* do it only if we have freetype up and running */
3307 EnterCriticalSection( &freetype_cs
);
3309 if ((unixname
= wine_get_unix_file_name(file
)))
3311 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3313 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3314 ret
= remove_font_resource( unixname
, addfont_flags
);
3315 HeapFree(GetProcessHeap(), 0, unixname
);
3317 if (!ret
&& !strchrW(file
, '\\'))
3319 if ((unixname
= get_winfonts_dir_path( file
)))
3321 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3322 HeapFree(GetProcessHeap(), 0, unixname
);
3324 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3326 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3327 HeapFree(GetProcessHeap(), 0, unixname
);
3331 LeaveCriticalSection( &freetype_cs
);
3336 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3342 if (!font_file
) return NULL
;
3344 file_len
= strlenW( font_file
);
3346 if (font_path
&& font_path
[0])
3348 int path_len
= strlenW( font_path
);
3349 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3350 if (!fullname
) return NULL
;
3351 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3352 fullname
[path_len
] = '\\';
3353 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3357 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3358 if (!len
) return NULL
;
3359 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3360 if (!fullname
) return NULL
;
3361 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3364 unix_name
= wine_get_unix_file_name( fullname
);
3365 HeapFree( GetProcessHeap(), 0, fullname
);
3369 #include <pshpack1.h>
3372 WORD num_of_resources
;
3376 CHAR dfCopyright
[60];
3382 WORD dfInternalLeading
;
3383 WORD dfExternalLeading
;
3391 BYTE dfPitchAndFamily
;
3402 CHAR szFaceName
[LF_FACESIZE
];
3405 #include <poppack.h>
3407 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3408 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3410 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3412 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3414 WCHAR
*name
, *english_name
;
3416 NEWTEXTMETRICEXW ntm
;
3419 if (!ft_face
) return FALSE
;
3420 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3421 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3422 pFT_Done_Face( ft_face
);
3424 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3425 release_face( face
);
3426 HeapFree( GetProcessHeap(), 0, name
);
3427 HeapFree( GetProcessHeap(), 0, english_name
);
3429 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3431 memset( fd
, 0, sizeof(*fd
) );
3433 fd
->num_of_resources
= 1;
3435 fd
->dfVersion
= 0x200;
3436 fd
->dfSize
= sizeof(*fd
);
3437 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3438 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3439 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3441 fd
->dfHorizRes
= 72;
3442 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3443 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3444 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3445 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3446 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3447 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3448 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3449 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3451 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3452 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3453 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3454 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3455 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3456 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3457 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3458 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3459 fd
->dfWidthBytes
= 0;
3461 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3463 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3468 #define NE_FFLAGS_LIBMODULE 0x8000
3469 #define NE_OSFLAGS_WINDOWS 0x02
3471 static const char dos_string
[0x40] = "This is a TrueType resource file";
3472 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3474 #include <pshpack2.h>
3495 struct ne_typeinfo fontdir_type
;
3496 struct ne_nameinfo fontdir_name
;
3497 struct ne_typeinfo scalable_type
;
3498 struct ne_nameinfo scalable_name
;
3500 BYTE fontdir_res_name
[8];
3503 #include <poppack.h>
3505 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3509 DWORD size
, written
;
3511 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3512 char *font_fileA
, *last_part
, *ext
;
3513 IMAGE_DOS_HEADER dos
;
3514 IMAGE_OS2_HEADER ne
=
3516 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3518 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3519 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3521 struct rsrc_tab rsrc_tab
=
3525 { 0, 0, 0x0c50, 0x2c, 0 },
3527 { 0, 0, 0x0c50, 0x8001, 0 },
3529 { 7,'F','O','N','T','D','I','R'}
3532 memset( &dos
, 0, sizeof(dos
) );
3533 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3534 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3536 /* import name is last part\0, resident name is last part without extension
3537 non-resident name is "FONTRES:" + lfFaceName */
3539 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3540 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3541 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3543 last_part
= strrchr( font_fileA
, '\\' );
3544 if (last_part
) last_part
++;
3545 else last_part
= font_fileA
;
3546 import_name_len
= strlen( last_part
) + 1;
3548 ext
= strchr( last_part
, '.' );
3549 if (ext
) res_name_len
= ext
- last_part
;
3550 else res_name_len
= import_name_len
- 1;
3552 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3554 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3555 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3556 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3557 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3559 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3561 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3562 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3563 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3564 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3566 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3567 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3571 HeapFree( GetProcessHeap(), 0, font_fileA
);
3575 memcpy( ptr
, &dos
, sizeof(dos
) );
3576 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3577 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3579 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3580 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3582 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3583 *ptr
++ = res_name_len
;
3584 memcpy( ptr
, last_part
, res_name_len
);
3586 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3587 *ptr
++ = import_name_len
;
3588 memcpy( ptr
, last_part
, import_name_len
);
3590 ptr
= start
+ ne
.ne_nrestab
;
3591 *ptr
++ = non_res_name_len
;
3592 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3593 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3595 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3596 memcpy( ptr
, font_fileA
, font_file_len
);
3598 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3599 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3601 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3602 if (file
!= INVALID_HANDLE_VALUE
)
3604 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3606 CloseHandle( file
);
3609 HeapFree( GetProcessHeap(), 0, start
);
3610 HeapFree( GetProcessHeap(), 0, font_fileA
);
3615 /*************************************************************
3616 * WineEngCreateScalableFontResource
3619 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3620 LPCWSTR font_file
, LPCWSTR font_path
)
3622 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3623 struct fontdir fontdir
;
3626 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3627 SetLastError( ERROR_INVALID_PARAMETER
);
3630 if (hidden
) fontdir
.dfType
|= 0x80;
3631 ret
= create_fot( resource
, font_file
, &fontdir
);
3634 HeapFree( GetProcessHeap(), 0, unix_name
);
3638 static const struct nls_update_font_list
3640 UINT ansi_cp
, oem_cp
;
3641 const char *oem
, *fixed
, *system
;
3642 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3643 /* these are for font substitutes */
3644 const char *shelldlg
, *tmsrmn
;
3645 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3649 const char *from
, *to
;
3650 } arial_0
, courier_new_0
, times_new_roman_0
;
3651 } nls_update_font_list
[] =
3653 /* Latin 1 (United States) */
3654 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3655 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3656 "Tahoma","Times New Roman",
3657 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3660 /* Latin 1 (Multilingual) */
3661 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3662 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3663 "Tahoma","Times New Roman", /* FIXME unverified */
3664 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3667 /* Eastern Europe */
3668 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3669 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3670 "Tahoma","Times New Roman", /* FIXME unverified */
3671 "Fixedsys,238", "System,238",
3672 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3673 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3674 { "Arial CE,0", "Arial,238" },
3675 { "Courier New CE,0", "Courier New,238" },
3676 { "Times New Roman CE,0", "Times New Roman,238" }
3679 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3680 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3681 "Tahoma","Times New Roman", /* FIXME unverified */
3682 "Fixedsys,204", "System,204",
3683 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3684 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3685 { "Arial Cyr,0", "Arial,204" },
3686 { "Courier New Cyr,0", "Courier New,204" },
3687 { "Times New Roman Cyr,0", "Times New Roman,204" }
3690 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3691 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3692 "Tahoma","Times New Roman", /* FIXME unverified */
3693 "Fixedsys,161", "System,161",
3694 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3695 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3696 { "Arial Greek,0", "Arial,161" },
3697 { "Courier New Greek,0", "Courier New,161" },
3698 { "Times New Roman Greek,0", "Times New Roman,161" }
3701 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3702 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3703 "Tahoma","Times New Roman", /* FIXME unverified */
3704 "Fixedsys,162", "System,162",
3705 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3706 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3707 { "Arial Tur,0", "Arial,162" },
3708 { "Courier New Tur,0", "Courier New,162" },
3709 { "Times New Roman Tur,0", "Times New Roman,162" }
3712 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3713 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3714 "Tahoma","Times New Roman", /* FIXME unverified */
3715 "Fixedsys,177", "System,177",
3716 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3717 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3721 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3722 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3723 "Microsoft Sans Serif","Times New Roman",
3724 "Fixedsys,178", "System,178",
3725 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3726 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3730 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3731 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3732 "Tahoma","Times New Roman", /* FIXME unverified */
3733 "Fixedsys,186", "System,186",
3734 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3735 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3736 { "Arial Baltic,0", "Arial,186" },
3737 { "Courier New Baltic,0", "Courier New,186" },
3738 { "Times New Roman Baltic,0", "Times New Roman,186" }
3741 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3742 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3743 "Tahoma","Times New Roman", /* FIXME unverified */
3744 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3748 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3749 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3750 "Tahoma","Times New Roman", /* FIXME unverified */
3751 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3755 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3756 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3757 "MS UI Gothic","MS Serif",
3758 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3761 /* Chinese Simplified */
3762 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3763 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3764 "SimSun", "NSimSun",
3765 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3769 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3770 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3772 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3775 /* Chinese Traditional */
3776 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3777 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3778 "PMingLiU", "MingLiU",
3779 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3784 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3786 return ( ansi_cp
== 932 /* CP932 for Japanese */
3787 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3788 || ansi_cp
== 949 /* CP949 for Korean */
3789 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3792 static inline HKEY
create_fonts_NT_registry_key(void)
3796 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3797 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3801 static inline HKEY
create_fonts_9x_registry_key(void)
3805 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3806 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3810 static inline HKEY
create_config_fonts_registry_key(void)
3814 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3815 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3819 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3821 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3823 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3824 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3825 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3826 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3829 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3832 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3834 RegDeleteValueA(hkey
, name
);
3837 static void update_font_association_info(UINT current_ansi_codepage
)
3839 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3840 static const char *assoc_charset_subkey
= "Associated Charset";
3842 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3845 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3848 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3850 switch (current_ansi_codepage
)
3853 set_value_key(hsubkey
, "ANSI(00)", "NO");
3854 set_value_key(hsubkey
, "OEM(FF)", "NO");
3855 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3860 set_value_key(hsubkey
, "ANSI(00)", "YES");
3861 set_value_key(hsubkey
, "OEM(FF)", "YES");
3862 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3865 RegCloseKey(hsubkey
);
3868 /* TODO: Associated DefaultFonts */
3874 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3877 static void set_multi_value_key(HKEY hkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD len
)
3880 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (const BYTE
*)value
, len
);
3882 RegDeleteValueW(hkey
, name
);
3885 static void update_font_system_link_info(UINT current_ansi_codepage
)
3887 static const WCHAR system_link_simplified_chinese
[] =
3888 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3889 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3890 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3891 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3893 static const WCHAR system_link_traditional_chinese
[] =
3894 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3895 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3896 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3897 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3899 static const WCHAR system_link_japanese
[] =
3900 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3901 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3902 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3903 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3905 static const WCHAR system_link_korean
[] =
3906 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3907 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3908 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3909 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3911 static const WCHAR system_link_non_cjk
[] =
3912 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3913 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3914 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3915 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3919 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
3924 switch (current_ansi_codepage
)
3927 link
= system_link_japanese
;
3928 len
= sizeof(system_link_japanese
);
3931 link
= system_link_simplified_chinese
;
3932 len
= sizeof(system_link_simplified_chinese
);
3935 link
= system_link_korean
;
3936 len
= sizeof(system_link_korean
);
3939 link
= system_link_traditional_chinese
;
3940 len
= sizeof(system_link_traditional_chinese
);
3943 link
= system_link_non_cjk
;
3944 len
= sizeof(system_link_non_cjk
);
3946 set_multi_value_key(hkey
, Lucida_Sans_Unicode
, link
, len
);
3947 set_multi_value_key(hkey
, Microsoft_Sans_Serif
, link
, len
);
3948 set_multi_value_key(hkey
, Tahoma
, link
, len
);
3953 static void update_font_info(void)
3955 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3956 char buf
[40], cpbuf
[40];
3959 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3960 DWORD screen_dpi
= 96, font_dpi
= 0;
3963 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3964 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3965 &hkey
) == ERROR_SUCCESS
)
3967 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3971 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3974 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3976 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3977 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3978 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3979 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3980 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3982 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3983 if (is_dbcs_ansi_cp(ansi_cp
))
3984 use_default_fallback
= TRUE
;
3988 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3990 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3995 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3996 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3998 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3999 ansi_cp
, oem_cp
, screen_dpi
);
4001 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
4002 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
4005 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
4009 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
4010 nls_update_font_list
[i
].oem_cp
== oem_cp
)
4012 hkey
= create_config_fonts_registry_key();
4013 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
4014 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
4015 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
4018 hkey
= create_fonts_NT_registry_key();
4019 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
4022 hkey
= create_fonts_9x_registry_key();
4023 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
4026 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
4028 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
4029 strlen(nls_update_font_list
[i
].shelldlg
)+1);
4030 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
4031 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
4033 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
4034 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
4035 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
4036 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
4037 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
4038 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
4039 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
4040 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
4042 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
4043 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
4044 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
4052 /* Delete the FontSubstitutes from other locales */
4053 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
4055 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
4056 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
4057 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
4063 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
4065 /* update locale dependent font association info and font system link info in registry.
4066 update only when codepages changed, not logpixels. */
4067 if (strcmp(buf
, cpbuf
) != 0)
4069 update_font_association_info(ansi_cp
);
4070 update_font_system_link_info(ansi_cp
);
4074 static BOOL
init_freetype(void)
4076 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
4079 "Wine cannot find the FreeType font library. To enable Wine to\n"
4080 "use TrueType fonts please install a version of FreeType greater than\n"
4081 "or equal to 2.0.5.\n"
4082 "http://www.freetype.org\n");
4086 #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;}
4088 LOAD_FUNCPTR(FT_Done_Face
)
4089 LOAD_FUNCPTR(FT_Get_Char_Index
)
4090 LOAD_FUNCPTR(FT_Get_First_Char
)
4091 LOAD_FUNCPTR(FT_Get_Next_Char
)
4092 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
4093 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
4094 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
4095 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
4096 LOAD_FUNCPTR(FT_Init_FreeType
)
4097 LOAD_FUNCPTR(FT_Library_Version
)
4098 LOAD_FUNCPTR(FT_Load_Glyph
)
4099 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
4100 LOAD_FUNCPTR(FT_Matrix_Multiply
)
4101 #ifndef FT_MULFIX_INLINED
4102 LOAD_FUNCPTR(FT_MulFix
)
4104 LOAD_FUNCPTR(FT_New_Face
)
4105 LOAD_FUNCPTR(FT_New_Memory_Face
)
4106 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
4107 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
4108 LOAD_FUNCPTR(FT_Outline_Transform
)
4109 LOAD_FUNCPTR(FT_Outline_Translate
)
4110 LOAD_FUNCPTR(FT_Render_Glyph
)
4111 LOAD_FUNCPTR(FT_Select_Charmap
)
4112 LOAD_FUNCPTR(FT_Set_Charmap
)
4113 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
4114 LOAD_FUNCPTR(FT_Vector_Length
)
4115 LOAD_FUNCPTR(FT_Vector_Transform
)
4116 LOAD_FUNCPTR(FT_Vector_Unit
)
4118 /* Don't warn if these ones are missing */
4119 pFT_Outline_Embolden
= wine_dlsym(ft_handle
, "FT_Outline_Embolden", NULL
, 0);
4120 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
4121 #ifdef FT_LCD_FILTER_H
4122 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
4125 if(pFT_Init_FreeType(&library
) != 0) {
4126 ERR("Can't init FreeType library\n");
4127 wine_dlclose(ft_handle
, NULL
, 0);
4131 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
4133 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
4134 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
4135 ((FT_Version
.minor
<< 8) & 0x00ff00) |
4136 ((FT_Version
.patch
) & 0x0000ff);
4138 font_driver
= &freetype_funcs
;
4143 "Wine cannot find certain functions that it needs inside the FreeType\n"
4144 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4145 "FreeType to at least version 2.1.4.\n"
4146 "http://www.freetype.org\n");
4147 wine_dlclose(ft_handle
, NULL
, 0);
4152 static void init_font_list(void)
4154 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
4155 static const WCHAR pathW
[] = {'P','a','t','h',0};
4157 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
4158 WCHAR windowsdir
[MAX_PATH
];
4161 delete_external_font_keys();
4163 /* load the system bitmap fonts */
4164 load_system_fonts();
4166 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4167 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
4168 strcatW(windowsdir
, fontsW
);
4169 if((unixname
= wine_get_unix_file_name(windowsdir
)))
4171 ReadFontDir(unixname
, FALSE
);
4172 HeapFree(GetProcessHeap(), 0, unixname
);
4175 /* load the wine fonts */
4176 if ((unixname
= get_font_dir()))
4178 ReadFontDir(unixname
, TRUE
);
4179 HeapFree(GetProcessHeap(), 0, unixname
);
4182 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4183 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4184 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4186 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
4187 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
4188 &hkey
) == ERROR_SUCCESS
)
4190 LPWSTR data
, valueW
;
4191 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4192 &valuelen
, &datalen
, NULL
, NULL
);
4194 valuelen
++; /* returned value doesn't include room for '\0' */
4195 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
4196 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
4199 dlen
= datalen
* sizeof(WCHAR
);
4201 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
4202 &dlen
) == ERROR_SUCCESS
)
4204 if(data
[0] && (data
[1] == ':'))
4206 if((unixname
= wine_get_unix_file_name(data
)))
4208 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4209 HeapFree(GetProcessHeap(), 0, unixname
);
4212 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
4214 WCHAR pathW
[MAX_PATH
];
4215 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
4218 sprintfW(pathW
, fmtW
, windowsdir
, data
);
4219 if((unixname
= wine_get_unix_file_name(pathW
)))
4221 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4222 HeapFree(GetProcessHeap(), 0, unixname
);
4225 load_font_from_data_dir(data
);
4227 /* reset dlen and vlen */
4232 HeapFree(GetProcessHeap(), 0, data
);
4233 HeapFree(GetProcessHeap(), 0, valueW
);
4237 #ifdef SONAME_LIBFONTCONFIG
4238 load_fontconfig_fonts();
4239 #elif defined(HAVE_CARBON_CARBON_H)
4241 #elif defined(__ANDROID__)
4242 ReadFontDir("/system/fonts", TRUE
);
4245 /* then look in any directories that we've specified in the config file */
4246 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4247 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
4253 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
4255 len
+= sizeof(WCHAR
);
4256 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
4257 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
4259 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
4260 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
4261 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
4262 TRACE( "got font path %s\n", debugstr_a(valueA
) );
4267 LPSTR next
= strchr( ptr
, ':' );
4268 if (next
) *next
++ = 0;
4269 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
4270 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
4272 strcpy( unixname
, home
);
4273 strcat( unixname
, ptr
+ 1 );
4274 ReadFontDir( unixname
, TRUE
);
4275 HeapFree( GetProcessHeap(), 0, unixname
);
4278 ReadFontDir( ptr
, TRUE
);
4281 HeapFree( GetProcessHeap(), 0, valueA
);
4283 HeapFree( GetProcessHeap(), 0, valueW
);
4289 static BOOL
move_to_front(const WCHAR
*name
)
4291 Family
*family
, *cursor2
;
4292 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
4294 if(!strcmpiW(family
->FamilyName
, name
))
4296 list_remove(&family
->entry
);
4297 list_add_head(&font_list
, &family
->entry
);
4304 static BOOL
set_default(const WCHAR
**name_list
)
4308 if (move_to_front(*name_list
)) return TRUE
;
4315 static void reorder_font_list(void)
4317 set_default( default_serif_list
);
4318 set_default( default_fixed_list
);
4319 set_default( default_sans_list
);
4322 /*************************************************************
4325 * Initialize FreeType library and create a list of available faces
4327 BOOL
WineEngInit(void)
4333 /* update locale dependent font info in registry */
4336 if(!init_freetype()) return FALSE
;
4338 #ifdef SONAME_LIBFONTCONFIG
4342 if (!RegOpenKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, KEY_READ
, &hkey
))
4344 static const WCHAR antialias_fake_bold_or_italic
[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4345 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4346 static const WCHAR true_options
[] = { 'y','Y','t','T','1',0 };
4350 size
= sizeof(buffer
);
4351 if (!RegQueryValueExW(hkey
, antialias_fake_bold_or_italic
, NULL
, &type
, (BYTE
*)buffer
, &size
) &&
4352 type
== REG_SZ
&& size
>= 1)
4354 antialias_fakes
= (strchrW(true_options
, buffer
[0]) != NULL
);
4359 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
4361 ERR("Failed to create font mutex\n");
4364 WaitForSingleObject(font_mutex
, INFINITE
);
4366 create_font_cache_key(&hkey_font_cache
, &disposition
);
4368 if(disposition
== REG_CREATED_NEW_KEY
)
4371 load_font_list_from_cache(hkey_font_cache
);
4373 reorder_font_list();
4380 if(disposition
== REG_CREATED_NEW_KEY
)
4381 update_reg_entries();
4383 init_system_links();
4385 ReleaseMutex(font_mutex
);
4389 /* Some fonts have large usWinDescent values, as a result of storing signed short
4390 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4391 some font generation tools. */
4392 static inline USHORT
get_fixed_windescent(USHORT windescent
)
4394 return abs((SHORT
)windescent
);
4397 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
4400 TT_HoriHeader
*pHori
;
4403 const LONG MAX_PPEM
= (1 << 16) - 1;
4405 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4406 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4408 if(height
== 0) height
= 16;
4410 /* Calc. height of EM square:
4412 * For +ve lfHeight we have
4413 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4414 * Re-arranging gives:
4415 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4417 * For -ve lfHeight we have
4419 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4420 * with il = winAscent + winDescent - units_per_em]
4425 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
4426 if(pOS2
->usWinAscent
+ windescent
== 0)
4427 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4428 pHori
->Ascender
- pHori
->Descender
);
4430 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4431 pOS2
->usWinAscent
+ windescent
);
4432 if(ppem
> MAX_PPEM
) {
4433 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4437 else if(height
>= -MAX_PPEM
)
4440 WARN("Ignoring too large height %d\n", height
);
4447 static struct font_mapping
*map_font_file( const char *name
)
4449 struct font_mapping
*mapping
;
4453 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4454 if (fstat( fd
, &st
) == -1) goto error
;
4456 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4458 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4460 mapping
->refcount
++;
4465 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4468 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4471 if (mapping
->data
== MAP_FAILED
)
4473 HeapFree( GetProcessHeap(), 0, mapping
);
4476 mapping
->refcount
= 1;
4477 mapping
->dev
= st
.st_dev
;
4478 mapping
->ino
= st
.st_ino
;
4479 mapping
->size
= st
.st_size
;
4480 list_add_tail( &mappings_list
, &mapping
->entry
);
4488 static void unmap_font_file( struct font_mapping
*mapping
)
4490 if (!--mapping
->refcount
)
4492 list_remove( &mapping
->entry
);
4493 munmap( mapping
->data
, mapping
->size
);
4494 HeapFree( GetProcessHeap(), 0, mapping
);
4498 static LONG
load_VDMX(GdiFont
*, LONG
);
4500 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4507 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4511 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4512 font
->mapping
= map_font_file( filename
);
4513 HeapFree( GetProcessHeap(), 0, filename
);
4516 WARN("failed to map %s\n", debugstr_w(face
->file
));
4519 data_ptr
= font
->mapping
->data
;
4520 data_size
= font
->mapping
->size
;
4524 data_ptr
= face
->font_data_ptr
;
4525 data_size
= face
->font_data_size
;
4528 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4530 ERR("FT_New_Face rets %d\n", err
);
4534 /* set it here, as load_VDMX needs it */
4535 font
->ft_face
= ft_face
;
4537 if(FT_IS_SCALABLE(ft_face
)) {
4538 /* load the VDMX table if we have one */
4539 font
->ppem
= load_VDMX(font
, height
);
4541 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4542 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4544 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4545 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4547 font
->ppem
= height
;
4548 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4549 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4555 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4557 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4558 a single face with the requested charset. The idea is to check if
4559 the selected font supports the current ANSI codepage, if it does
4560 return the corresponding charset, else return the first charset */
4563 int acp
= GetACP(), i
;
4567 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4569 const SYSTEM_LINKS
*font_link
;
4571 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4572 return csi
.ciCharset
;
4574 font_link
= find_font_link(family_name
);
4575 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4576 return csi
.ciCharset
;
4579 for(i
= 0; i
< 32; i
++) {
4581 if(face
->fs
.fsCsb
[0] & fs0
) {
4582 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4584 return csi
.ciCharset
;
4587 FIXME("TCI failing on %x\n", fs0
);
4591 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4592 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4594 return DEFAULT_CHARSET
;
4597 static GdiFont
*alloc_font(void)
4599 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4602 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4603 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4605 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4606 ret
->total_kern_pairs
= (DWORD
)-1;
4607 ret
->kern_pairs
= NULL
;
4608 ret
->instance_id
= alloc_font_handle(ret
);
4609 list_init(&ret
->child_fonts
);
4613 static void free_font(GdiFont
*font
)
4615 CHILD_FONT
*child
, *child_next
;
4618 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4620 list_remove(&child
->entry
);
4622 free_font(child
->font
);
4623 release_face( child
->face
);
4624 HeapFree(GetProcessHeap(), 0, child
);
4627 HeapFree(GetProcessHeap(), 0, font
->fileinfo
);
4628 free_font_handle(font
->instance_id
);
4629 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4630 if (font
->mapping
) unmap_font_file( font
->mapping
);
4631 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4632 HeapFree(GetProcessHeap(), 0, font
->potm
);
4633 HeapFree(GetProcessHeap(), 0, font
->name
);
4634 for (i
= 0; i
< font
->gmsize
; i
++)
4635 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4636 HeapFree(GetProcessHeap(), 0, font
->gm
);
4637 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4638 HeapFree(GetProcessHeap(), 0, font
);
4642 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4644 FT_Face ft_face
= font
->ft_face
;
4648 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4655 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4657 /* make sure value of len is the value freetype says it needs */
4660 FT_ULong needed
= 0;
4661 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4662 if( !err
&& needed
< len
) len
= needed
;
4664 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4667 TRACE("Can't find table %c%c%c%c\n",
4668 /* bytes were reversed */
4669 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4670 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4676 /*************************************************************
4679 * load the vdmx entry for the specified height
4682 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4683 ( ( (FT_ULong)_x4 << 24 ) | \
4684 ( (FT_ULong)_x3 << 16 ) | \
4685 ( (FT_ULong)_x2 << 8 ) | \
4688 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4715 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4719 BYTE devXRatio
, devYRatio
;
4720 USHORT numRecs
, numRatios
;
4721 DWORD result
, offset
= -1;
4725 result
= get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
4727 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4730 /* FIXME: need the real device aspect ratio */
4734 numRecs
= GET_BE_WORD(hdr
.numRecs
);
4735 numRatios
= GET_BE_WORD(hdr
.numRatios
);
4737 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
4738 for(i
= 0; i
< numRatios
; i
++) {
4741 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
4742 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4745 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4747 if (!ratio
.bCharSet
) continue;
4749 if((ratio
.xRatio
== 0 &&
4750 ratio
.yStartRatio
== 0 &&
4751 ratio
.yEndRatio
== 0) ||
4752 (devXRatio
== ratio
.xRatio
&&
4753 devYRatio
>= ratio
.yStartRatio
&&
4754 devYRatio
<= ratio
.yEndRatio
))
4758 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
4759 get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
4760 offset
= GET_BE_WORD(group_offset
);
4765 if(offset
== -1) return 0;
4767 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
4769 BYTE startsz
, endsz
;
4772 recs
= GET_BE_WORD(group
.recs
);
4773 startsz
= group
.startsz
;
4774 endsz
= group
.endsz
;
4776 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4778 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
4779 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
4780 if(result
== GDI_ERROR
) {
4781 FIXME("Failed to retrieve vTable\n");
4786 for(i
= 0; i
< recs
; i
++) {
4787 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4788 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4789 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4791 if(yMax
+ -yMin
== height
) {
4794 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4797 if(yMax
+ -yMin
> height
) {
4800 goto end
; /* failed */
4802 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4803 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4804 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4805 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4811 TRACE("ppem not found for height %d\n", height
);
4815 if(ppem
< startsz
|| ppem
> endsz
)
4821 for(i
= 0; i
< recs
; i
++) {
4823 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4825 if(yPelHeight
> ppem
)
4831 if(yPelHeight
== ppem
) {
4832 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4833 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4834 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4840 HeapFree(GetProcessHeap(), 0, vTable
);
4846 static void dump_gdi_font_list(void)
4850 TRACE("---------- Font Cache ----------\n");
4851 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4852 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4853 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4856 static void grab_font( GdiFont
*font
)
4858 if (!font
->refcount
++)
4860 list_remove( &font
->unused_entry
);
4861 unused_font_count
--;
4865 static void release_font( GdiFont
*font
)
4868 if (!--font
->refcount
)
4870 TRACE( "font %p\n", font
);
4872 /* add it to the unused list */
4873 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4874 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4876 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4877 TRACE( "freeing %p\n", font
);
4878 list_remove( &font
->entry
);
4879 list_remove( &font
->unused_entry
);
4882 else unused_font_count
++;
4884 if (TRACE_ON(font
)) dump_gdi_font_list();
4888 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4890 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4891 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4892 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4893 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4894 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4897 static void calc_hash(FONT_DESC
*pfd
)
4899 DWORD hash
= 0, *ptr
, two_chars
;
4903 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4905 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4907 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4909 pwc
= (WCHAR
*)&two_chars
;
4911 *pwc
= toupperW(*pwc
);
4913 *pwc
= toupperW(*pwc
);
4917 hash
^= !pfd
->can_use_bitmap
;
4921 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4928 fd
.can_use_bitmap
= can_use_bitmap
;
4931 /* try the in-use list */
4932 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4934 if(fontcmp(ret
, &fd
)) continue;
4935 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4936 list_remove( &ret
->entry
);
4937 list_add_head( &gdi_font_list
, &ret
->entry
);
4944 static void add_to_cache(GdiFont
*font
)
4946 static DWORD cache_num
= 1;
4948 font
->cache_num
= cache_num
++;
4949 list_add_head(&gdi_font_list
, &font
->entry
);
4950 TRACE( "font %p\n", font
);
4953 /*************************************************************
4954 * create_child_font_list
4956 static BOOL
create_child_font_list(GdiFont
*font
)
4959 SYSTEM_LINKS
*font_link
;
4960 CHILD_FONT
*font_link_entry
, *new_child
;
4964 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4965 font_name
= psub
? psub
->to
.name
: font
->name
;
4966 font_link
= find_font_link(font_name
);
4967 if (font_link
!= NULL
)
4969 TRACE("found entry in system 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
);
4982 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4983 * Sans Serif. This is how asian windows get default fallbacks for fonts
4985 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4986 font
->charset
!= OEM_CHARSET
&&
4987 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4989 font_link
= find_font_link(szDefaultFallbackLink
);
4990 if (font_link
!= NULL
)
4992 TRACE("found entry in default fallback list\n");
4993 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4995 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4996 new_child
->face
= font_link_entry
->face
;
4997 new_child
->font
= NULL
;
4998 new_child
->face
->refcount
++;
4999 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
5000 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
5009 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
5011 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
5013 if (pFT_Set_Charmap
)
5016 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
5018 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
5020 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
5022 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
5024 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5025 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
5027 switch (ft_face
->charmaps
[i
]->platform_id
)
5030 cmap_def
= ft_face
->charmaps
[i
];
5032 case 0: /* Apple Unicode */
5033 cmap0
= ft_face
->charmaps
[i
];
5035 case 1: /* Macintosh */
5036 cmap1
= ft_face
->charmaps
[i
];
5039 cmap2
= ft_face
->charmaps
[i
];
5041 case 3: /* Microsoft */
5042 cmap3
= ft_face
->charmaps
[i
];
5047 if (cmap3
) /* prefer Microsoft cmap table */
5048 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
5050 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
5052 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
5054 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
5056 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
5058 return ft_err
== FT_Err_Ok
;
5061 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
5065 /*************************************************************
5068 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
5069 LPCWSTR output
, const DEVMODEW
*devmode
)
5071 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
5073 if (!physdev
) return FALSE
;
5074 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
5079 /*************************************************************
5082 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
5084 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5085 release_font( physdev
->font
);
5086 HeapFree( GetProcessHeap(), 0, physdev
);
5090 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
5092 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
5093 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
5094 const FT_Encoding
*encs
= regular_order
;
5096 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
5100 if (select_charmap( face
, *encs
)) break;
5106 #define GASP_GRIDFIT 0x01
5107 #define GASP_DOGRAY 0x02
5108 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
5110 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
5113 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
5114 WORD
*alloced
= NULL
, *ptr
= buf
;
5115 WORD num_recs
, version
;
5119 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
5120 if (size
== GDI_ERROR
) return FALSE
;
5121 if (size
< 4 * sizeof(WORD
)) return FALSE
;
5122 if (size
> sizeof(buf
))
5124 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
5125 if (!ptr
) return FALSE
;
5128 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
5130 version
= GET_BE_WORD( *ptr
++ );
5131 num_recs
= GET_BE_WORD( *ptr
++ );
5133 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
5135 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
5141 *flags
= GET_BE_WORD( *(ptr
+ 1) );
5142 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
5145 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
5149 HeapFree( GetProcessHeap(), 0, alloced
);
5153 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5155 const GSUB_ScriptList
*script
;
5156 const GSUB_Script
*deflt
= NULL
;
5158 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5160 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5161 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5163 const GSUB_Script
*scr
;
5166 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5167 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5169 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5171 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5177 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5181 const GSUB_LangSys
*Lang
;
5183 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5185 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5187 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5188 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5190 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5193 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5196 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5202 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5205 const GSUB_FeatureList
*feature
;
5206 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5208 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5209 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5211 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5212 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5214 const GSUB_Feature
*feat
;
5215 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5222 static const char* get_opentype_script(const GdiFont
*font
)
5225 * I am not sure if this is the correct way to generate our script tag
5228 switch (font
->charset
)
5230 case ANSI_CHARSET
: return "latn";
5231 case BALTIC_CHARSET
: return "latn"; /* ?? */
5232 case CHINESEBIG5_CHARSET
: return "hani";
5233 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5234 case GB2312_CHARSET
: return "hani";
5235 case GREEK_CHARSET
: return "grek";
5236 case HANGUL_CHARSET
: return "hang";
5237 case RUSSIAN_CHARSET
: return "cyrl";
5238 case SHIFTJIS_CHARSET
: return "kana";
5239 case TURKISH_CHARSET
: return "latn"; /* ?? */
5240 case VIETNAMESE_CHARSET
: return "latn";
5241 case JOHAB_CHARSET
: return "latn"; /* ?? */
5242 case ARABIC_CHARSET
: return "arab";
5243 case HEBREW_CHARSET
: return "hebr";
5244 case THAI_CHARSET
: return "thai";
5245 default: return "latn";
5249 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
5251 const GSUB_Header
*header
;
5252 const GSUB_Script
*script
;
5253 const GSUB_LangSys
*language
;
5254 const GSUB_Feature
*feature
;
5256 if (!font
->GSUB_Table
)
5259 header
= font
->GSUB_Table
;
5261 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5264 TRACE("Script not found\n");
5267 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5270 TRACE("Language not found\n");
5273 feature
= GSUB_get_feature(header
, language
, "vrt2");
5275 feature
= GSUB_get_feature(header
, language
, "vert");
5278 TRACE("vrt2/vert feature not found\n");
5284 static void fill_fileinfo_from_face( GdiFont
*font
, Face
*face
)
5286 WIN32_FILE_ATTRIBUTE_DATA info
;
5291 font
->fileinfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*font
->fileinfo
));
5295 len
= strlenW(face
->file
);
5296 font
->fileinfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font
->fileinfo
) + len
* sizeof(WCHAR
));
5297 if (GetFileAttributesExW(face
->file
, GetFileExInfoStandard
, &info
))
5299 font
->fileinfo
->writetime
= info
.ftLastWriteTime
;
5300 font
->fileinfo
->size
.QuadPart
= (LONGLONG
)info
.nFileSizeHigh
<< 32 | info
.nFileSizeLow
;
5301 strcpyW(font
->fileinfo
->path
, face
->file
);
5304 memset(font
->fileinfo
, 0, sizeof(*font
->fileinfo
) + len
* sizeof(WCHAR
));
5307 /*************************************************************
5308 * freetype_SelectFont
5310 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5312 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5314 Face
*face
, *best
, *best_bitmap
;
5315 Family
*family
, *last_resort_family
;
5316 const struct list
*face_list
;
5317 INT height
, width
= 0;
5318 unsigned int score
= 0, new_score
;
5319 signed int diff
= 0, newdiff
;
5320 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5324 FontSubst
*psub
= NULL
;
5325 DC
*dc
= get_dc_ptr( dev
->hdc
);
5326 const SYSTEM_LINKS
*font_link
;
5328 if (!hfont
) /* notification that the font has been changed by another driver */
5330 release_font( physdev
->font
);
5331 physdev
->font
= NULL
;
5332 release_dc_ptr( dc
);
5336 GetObjectW( hfont
, sizeof(lf
), &lf
);
5337 lf
.lfWidth
= abs(lf
.lfWidth
);
5339 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5341 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5342 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5343 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5346 if(dc
->GraphicsMode
== GM_ADVANCED
)
5348 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5349 /* Try to avoid not necessary glyph transformations */
5350 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5352 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5353 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5354 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5359 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5360 font scaling abilities. */
5361 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5362 dcmat
.eM21
= dcmat
.eM12
= 0;
5363 lf
.lfOrientation
= lf
.lfEscapement
;
5364 if (dc
->vport2WorldValid
)
5366 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5367 lf
.lfOrientation
= -lf
.lfOrientation
;
5368 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5369 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5373 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5374 dcmat
.eM21
, dcmat
.eM22
);
5377 EnterCriticalSection( &freetype_cs
);
5379 /* check the cache first */
5380 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5381 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5385 TRACE("not in cache\n");
5388 ret
->font_desc
.matrix
= dcmat
;
5389 ret
->font_desc
.lf
= lf
;
5390 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5391 calc_hash(&ret
->font_desc
);
5393 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5394 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5395 original value lfCharSet. Note this is a special case for
5396 Symbol and doesn't happen at least for "Wingdings*" */
5398 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5399 lf
.lfCharSet
= SYMBOL_CHARSET
;
5401 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5402 switch(lf
.lfCharSet
) {
5403 case DEFAULT_CHARSET
:
5404 csi
.fs
.fsCsb
[0] = 0;
5407 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5408 csi
.fs
.fsCsb
[0] = 0;
5414 if(lf
.lfFaceName
[0] != '\0') {
5415 CHILD_FONT
*font_link_entry
;
5416 LPWSTR FaceName
= lf
.lfFaceName
;
5418 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5421 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5422 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5423 if (psub
->to
.charset
!= -1)
5424 lf
.lfCharSet
= psub
->to
.charset
;
5427 /* We want a match on name and charset or just name if
5428 charset was DEFAULT_CHARSET. If the latter then
5429 we fixup the returned charset later in get_nearest_charset
5430 where we'll either use the charset of the current ansi codepage
5431 or if that's unavailable the first charset that the font supports.
5433 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5434 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5435 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5437 font_link
= find_font_link(family
->FamilyName
);
5438 face_list
= get_face_list_from_family(family
);
5439 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5440 if (!(face
->scalable
|| can_use_bitmap
))
5442 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5444 if (font_link
!= NULL
&&
5445 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5447 if (!csi
.fs
.fsCsb
[0])
5453 /* Search by full face name. */
5454 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5455 face_list
= get_face_list_from_family(family
);
5456 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5457 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5458 (face
->scalable
|| can_use_bitmap
))
5460 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5462 font_link
= find_font_link(family
->FamilyName
);
5463 if (font_link
!= NULL
&&
5464 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5471 * Try check the SystemLink list first for a replacement font.
5472 * We may find good replacements there.
5474 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5476 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5477 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5479 TRACE("found entry in system list\n");
5480 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5482 const SYSTEM_LINKS
*links
;
5484 face
= font_link_entry
->face
;
5485 if (!(face
->scalable
|| can_use_bitmap
))
5487 family
= face
->family
;
5488 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5490 links
= find_font_link(family
->FamilyName
);
5491 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5498 psub
= NULL
; /* substitution is no more relevant */
5500 /* If requested charset was DEFAULT_CHARSET then try using charset
5501 corresponding to the current ansi codepage */
5502 if (!csi
.fs
.fsCsb
[0])
5505 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5506 FIXME("TCI failed on codepage %d\n", acp
);
5507 csi
.fs
.fsCsb
[0] = 0;
5509 lf
.lfCharSet
= csi
.ciCharset
;
5512 want_vertical
= (lf
.lfFaceName
[0] == '@');
5514 /* Face families are in the top 4 bits of lfPitchAndFamily,
5515 so mask with 0xF0 before testing */
5517 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5518 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5519 strcpyW(lf
.lfFaceName
, defFixed
);
5520 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5521 strcpyW(lf
.lfFaceName
, defSerif
);
5522 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5523 strcpyW(lf
.lfFaceName
, defSans
);
5525 strcpyW(lf
.lfFaceName
, defSans
);
5526 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5527 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5528 font_link
= find_font_link(family
->FamilyName
);
5529 face_list
= get_face_list_from_family(family
);
5530 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5531 if (!(face
->scalable
|| can_use_bitmap
))
5533 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5535 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5541 last_resort_family
= NULL
;
5542 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5543 font_link
= find_font_link(family
->FamilyName
);
5544 face_list
= get_face_list_from_family(family
);
5545 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5546 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5547 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5548 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5551 if(can_use_bitmap
&& !last_resort_family
)
5552 last_resort_family
= family
;
5557 if(last_resort_family
) {
5558 family
= last_resort_family
;
5559 csi
.fs
.fsCsb
[0] = 0;
5563 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5564 face_list
= get_face_list_from_family(family
);
5565 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5566 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5567 csi
.fs
.fsCsb
[0] = 0;
5568 WARN("just using first face for now\n");
5571 if(can_use_bitmap
&& !last_resort_family
)
5572 last_resort_family
= family
;
5575 if(!last_resort_family
) {
5576 FIXME("can't find a single appropriate font - bailing\n");
5582 WARN("could only find a bitmap font - this will probably look awful!\n");
5583 family
= last_resort_family
;
5584 csi
.fs
.fsCsb
[0] = 0;
5587 it
= lf
.lfItalic
? 1 : 0;
5588 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5590 height
= lf
.lfHeight
;
5592 face
= best
= best_bitmap
= NULL
;
5593 font_link
= find_font_link(family
->FamilyName
);
5594 face_list
= get_face_list_from_family(family
);
5595 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5597 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5598 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5603 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5604 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5605 new_score
= (italic
^ it
) + (bold
^ bd
);
5606 if(!best
|| new_score
<= score
)
5608 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5609 italic
, bold
, it
, bd
);
5612 if(best
->scalable
&& score
== 0) break;
5616 newdiff
= height
- (signed int)(best
->size
.height
);
5618 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5619 if(!best_bitmap
|| new_score
< score
||
5620 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5622 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5625 if(score
== 0 && diff
== 0) break;
5632 face
= best
->scalable
? best
: best_bitmap
;
5633 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5634 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5637 height
= lf
.lfHeight
;
5641 if(csi
.fs
.fsCsb
[0]) {
5642 ret
->charset
= lf
.lfCharSet
;
5643 ret
->codepage
= csi
.ciACP
;
5646 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5648 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5649 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5651 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5653 if(!face
->scalable
) {
5654 /* Windows uses integer scaling factors for bitmap fonts */
5655 INT scale
, scaled_height
;
5656 GdiFont
*cachedfont
;
5658 /* FIXME: rotation of bitmap fonts is ignored */
5659 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5661 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5662 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5663 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5664 /* As we changed the matrix, we need to search the cache for the font again,
5665 * otherwise we might explode the cache. */
5666 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5667 TRACE("Found cached font after non-scalable matrix rescale!\n");
5672 calc_hash(&ret
->font_desc
);
5674 if (height
!= 0) height
= diff
;
5675 height
+= face
->size
.height
;
5677 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5678 scaled_height
= scale
* face
->size
.height
;
5679 /* Only jump to the next height if the difference <= 25% original height */
5680 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5681 /* The jump between unscaled and doubled is delayed by 1 */
5682 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5683 ret
->scale_y
= scale
;
5685 width
= face
->size
.x_ppem
>> 6;
5686 height
= face
->size
.y_ppem
>> 6;
5690 TRACE("font scale y: %f\n", ret
->scale_y
);
5692 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5701 fill_fileinfo_from_face( ret
, face
);
5702 ret
->ntmFlags
= face
->ntmFlags
;
5704 pick_charmap( ret
->ft_face
, ret
->charset
);
5706 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5707 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5708 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5709 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5710 create_child_font_list(ret
);
5712 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5714 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5715 if (length
!= GDI_ERROR
)
5717 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5718 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5719 TRACE("Loaded GSUB table of %i bytes\n",length
);
5720 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5721 if (!ret
->vert_feature
)
5723 TRACE("Vertical feature not found\n");
5724 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5725 ret
->GSUB_Table
= NULL
;
5729 ret
->aa_flags
= HIWORD( face
->flags
);
5731 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5737 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5739 switch (lf
.lfQuality
)
5741 case NONANTIALIASED_QUALITY
:
5742 case ANTIALIASED_QUALITY
:
5743 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5745 case CLEARTYPE_QUALITY
:
5746 case CLEARTYPE_NATURAL_QUALITY
:
5748 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5749 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5751 /* fixup the antialiasing flags for that font */
5754 case WINE_GGO_HRGB_BITMAP
:
5755 case WINE_GGO_HBGR_BITMAP
:
5756 case WINE_GGO_VRGB_BITMAP
:
5757 case WINE_GGO_VBGR_BITMAP
:
5758 if (is_subpixel_rendering_enabled()) break;
5759 *aa_flags
= GGO_GRAY4_BITMAP
;
5761 case GGO_GRAY2_BITMAP
:
5762 case GGO_GRAY4_BITMAP
:
5763 case GGO_GRAY8_BITMAP
:
5764 case WINE_GGO_GRAY16_BITMAP
:
5765 if ((!antialias_fakes
|| (!ret
->fake_bold
&& !ret
->fake_italic
)) && is_hinting_enabled())
5768 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5770 TRACE( "font %s %d aa disabled by GASP\n",
5771 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5772 *aa_flags
= GGO_BITMAP
;
5777 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5778 release_font( physdev
->font
);
5779 physdev
->font
= ret
;
5781 LeaveCriticalSection( &freetype_cs
);
5782 release_dc_ptr( dc
);
5783 return ret
? hfont
: 0;
5786 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5793 id
+= IDS_FIRST_SCRIPT
;
5794 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5795 if (!rsrc
) return 0;
5796 hMem
= LoadResource( gdi32_module
, rsrc
);
5797 if (!hMem
) return 0;
5799 p
= LockResource( hMem
);
5801 while (id
--) p
+= *p
+ 1;
5803 i
= min(LF_FACESIZE
- 1, *p
);
5804 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5809 static inline BOOL
is_complex_script_ansi_cp(UINT ansi_cp
)
5811 return (ansi_cp
== 874 /* Thai */
5812 || ansi_cp
== 1255 /* Hebrew */
5813 || ansi_cp
== 1256 /* Arabic */
5817 /***************************************************
5818 * create_enum_charset_list
5820 * This function creates charset enumeration list because in DEFAULT_CHARSET
5821 * case, the ANSI codepage's charset takes precedence over other charsets.
5822 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5823 * This function works as a filter other than DEFAULT_CHARSET case.
5825 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5830 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5831 csi
.fs
.fsCsb
[0] != 0) {
5832 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5833 list
->element
[n
].charset
= csi
.ciCharset
;
5834 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5837 else { /* charset is DEFAULT_CHARSET or invalid. */
5841 /* Set the current codepage's charset as the first element. */
5843 if (!is_complex_script_ansi_cp(acp
) &&
5844 TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5845 csi
.fs
.fsCsb
[0] != 0) {
5846 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5847 list
->element
[n
].charset
= csi
.ciCharset
;
5848 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5849 mask
|= csi
.fs
.fsCsb
[0];
5853 /* Fill out left elements. */
5854 for (i
= 0; i
< 32; i
++) {
5856 fs
.fsCsb
[0] = 1L << i
;
5858 if (fs
.fsCsb
[0] & mask
)
5859 continue; /* skip, already added. */
5860 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5861 continue; /* skip, this is an invalid fsCsb bit. */
5863 list
->element
[n
].mask
= fs
.fsCsb
[0];
5864 list
->element
[n
].charset
= csi
.ciCharset
;
5865 load_script_name( i
, list
->element
[n
].name
);
5866 mask
|= fs
.fsCsb
[0];
5870 /* add catch all mask for remaining bits */
5873 list
->element
[n
].mask
= ~mask
;
5874 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5875 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5884 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5885 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5890 if (face
->cached_enum_data
)
5893 *pelf
= face
->cached_enum_data
->elf
;
5894 *pntm
= face
->cached_enum_data
->ntm
;
5895 *ptype
= face
->cached_enum_data
->type
;
5899 font
= alloc_font();
5901 if(face
->scalable
) {
5905 height
= face
->size
.y_ppem
>> 6;
5906 width
= face
->size
.x_ppem
>> 6;
5908 font
->scale_y
= 1.0;
5910 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5916 font
->name
= strdupW( family_name
);
5917 font
->ntmFlags
= face
->ntmFlags
;
5919 if (get_outline_text_metrics(font
))
5921 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5923 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5924 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5925 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5927 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5928 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5930 lstrcpynW(pelf
->elfFullName
,
5931 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5933 lstrcpynW(pelf
->elfStyle
,
5934 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5939 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5941 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5942 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5943 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5945 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5947 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5949 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5950 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5953 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5954 pntm
->ntmFontSig
= face
->fs
;
5956 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5958 pelf
->elfLogFont
.lfEscapement
= 0;
5959 pelf
->elfLogFont
.lfOrientation
= 0;
5960 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5961 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5962 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5963 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5964 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5965 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5966 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5967 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5968 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5969 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5970 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5973 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5974 *ptype
|= TRUETYPE_FONTTYPE
;
5975 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5976 *ptype
|= DEVICE_FONTTYPE
;
5977 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5978 *ptype
|= RASTER_FONTTYPE
;
5980 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5981 if (face
->cached_enum_data
)
5983 face
->cached_enum_data
->elf
= *pelf
;
5984 face
->cached_enum_data
->ntm
= *pntm
;
5985 face
->cached_enum_data
->type
= *ptype
;
5991 static BOOL
family_matches(Family
*family
, const WCHAR
*face_name
)
5994 const struct list
*face_list
;
5996 if (!strcmpiW(face_name
, family
->FamilyName
)) return TRUE
;
5998 face_list
= get_face_list_from_family(family
);
5999 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
6000 if (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
)) return TRUE
;
6005 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const WCHAR
*face_name
)
6007 if (!strcmpiW(face_name
, family_name
)) return TRUE
;
6009 return (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
));
6012 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
6013 FONTENUMPROCW proc
, LPARAM lparam
, const WCHAR
*subst
)
6016 NEWTEXTMETRICEXW ntm
;
6020 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
6021 for(i
= 0; i
< list
->total
; i
++) {
6022 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
6023 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
6024 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
6025 i
= list
->total
; /* break out of loop after enumeration */
6029 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
6030 /* use the DEFAULT_CHARSET case only if no other charset is present */
6031 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
6032 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
6033 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
6034 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
6035 if (!elf
.elfScript
[0])
6036 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
6038 /* Font Replacement */
6039 if (family
!= face
->family
)
6041 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
6043 strcpyW(elf
.elfFullName
, face
->FullName
);
6045 strcpyW(elf
.elfFullName
, family
->FamilyName
);
6048 strcpyW(elf
.elfLogFont
.lfFaceName
, subst
);
6049 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6050 debugstr_w(elf
.elfLogFont
.lfFaceName
),
6051 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
6052 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
6053 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
6054 ntm
.ntmTm
.ntmFlags
);
6055 /* release section before callback (FIXME) */
6056 LeaveCriticalSection( &freetype_cs
);
6057 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
6058 EnterCriticalSection( &freetype_cs
);
6063 /*************************************************************
6064 * freetype_EnumFonts
6066 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6070 const struct list
*face_list
;
6072 struct enum_charset_list enum_charsets
;
6076 lf
.lfCharSet
= DEFAULT_CHARSET
;
6077 lf
.lfPitchAndFamily
= 0;
6078 lf
.lfFaceName
[0] = 0;
6082 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
6084 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
6087 EnterCriticalSection( &freetype_cs
);
6088 if(plf
->lfFaceName
[0]) {
6089 WCHAR
*face_name
= plf
->lfFaceName
;
6090 FontSubst
*psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
6093 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
6094 debugstr_w(psub
->to
.name
));
6095 face_name
= psub
->to
.name
;
6098 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
6099 if (!family_matches(family
, face_name
)) continue;
6100 face_list
= get_face_list_from_family(family
);
6101 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
6102 if (!face_matches(family
->FamilyName
, face
, face_name
)) continue;
6103 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, psub
? psub
->from
.name
: NULL
)) return FALSE
;
6107 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
6108 face_list
= get_face_list_from_family(family
);
6109 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
6110 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, NULL
)) return FALSE
;
6113 LeaveCriticalSection( &freetype_cs
);
6117 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
6119 pt
->x
.value
= vec
->x
>> 6;
6120 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
6121 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
6122 pt
->y
.value
= vec
->y
>> 6;
6123 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
6124 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
6127 /***************************************************
6128 * According to the MSDN documentation on WideCharToMultiByte,
6129 * certain codepages cannot set the default_used parameter.
6130 * This returns TRUE if the codepage can set that parameter, false else
6131 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6133 static BOOL
codepage_sets_default_used(UINT codepage
)
6147 * GSUB Table handling functions
6150 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
6152 const GSUB_CoverageFormat1
* cf1
;
6156 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
6158 int count
= GET_BE_WORD(cf1
->GlyphCount
);
6160 TRACE("Coverage Format 1, %i glyphs\n",count
);
6161 for (i
= 0; i
< count
; i
++)
6162 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
6166 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
6168 const GSUB_CoverageFormat2
* cf2
;
6171 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
6173 count
= GET_BE_WORD(cf2
->RangeCount
);
6174 TRACE("Coverage Format 2, %i ranges\n",count
);
6175 for (i
= 0; i
< count
; i
++)
6177 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
6179 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
6180 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
6182 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
6183 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
6189 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
6194 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
6198 const GSUB_LookupList
*lookup
;
6199 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
6201 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
6202 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
6204 const GSUB_LookupTable
*look
;
6205 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
6206 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
6207 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
6208 if (GET_BE_WORD(look
->LookupType
) != 1)
6209 FIXME("We only handle SubType 1\n");
6214 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
6216 const GSUB_SingleSubstFormat1
*ssf1
;
6217 offset
= GET_BE_WORD(look
->SubTable
[j
]);
6218 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
6219 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
6221 int offset
= GET_BE_WORD(ssf1
->Coverage
);
6222 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
6223 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
6225 TRACE(" Glyph 0x%x ->",glyph
);
6226 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
6227 TRACE(" 0x%x\n",glyph
);
6232 const GSUB_SingleSubstFormat2
*ssf2
;
6236 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
6237 offset
= GET_BE_WORD(ssf1
->Coverage
);
6238 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
6239 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
6240 TRACE(" Coverage index %i\n",index
);
6243 TRACE(" Glyph is 0x%x ->",glyph
);
6244 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
6245 TRACE("0x%x\n",glyph
);
6255 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
6257 const GSUB_Header
*header
;
6258 const GSUB_Feature
*feature
;
6260 if (!font
->GSUB_Table
)
6263 header
= font
->GSUB_Table
;
6264 feature
= font
->vert_feature
;
6266 return GSUB_apply_feature(header
, feature
, glyph
);
6269 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
6273 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6274 WCHAR wc
= (WCHAR
)glyph
;
6276 BOOL
*default_used_pointer
;
6279 default_used_pointer
= NULL
;
6280 default_used
= FALSE
;
6281 if (codepage_sets_default_used(font
->codepage
))
6282 default_used_pointer
= &default_used
;
6283 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6285 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6286 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6291 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6292 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6296 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6298 if (glyph
< 0x100) glyph
+= 0xf000;
6299 /* there is a number of old pre-Unicode "broken" TTFs, which
6300 do have symbols at U+00XX instead of U+f0XX */
6301 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6302 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6304 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6309 /* helper for freetype_GetGlyphIndices */
6310 static FT_UInt
get_gdi_glyph_index(const GdiFont
*font
, UINT glyph
)
6312 WCHAR wc
= (WCHAR
)glyph
;
6313 BOOL default_used
= FALSE
;
6314 BOOL
*default_used_pointer
= NULL
;
6318 if(font
->ft_face
->charmap
->encoding
!= FT_ENCODING_NONE
)
6319 return get_glyph_index(font
, glyph
);
6321 if (codepage_sets_default_used(font
->codepage
))
6322 default_used_pointer
= &default_used
;
6323 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
)
6326 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6327 ret
= (unsigned char)wc
;
6332 ret
= (unsigned char)buf
;
6333 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6337 static FT_UInt
get_default_char_index(GdiFont
*font
)
6339 FT_UInt default_char
;
6341 if (FT_IS_SFNT(font
->ft_face
))
6343 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6344 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6349 get_text_metrics(font
, &textm
);
6350 default_char
= textm
.tmDefaultChar
;
6353 return default_char
;
6356 /*************************************************************
6357 * freetype_GetGlyphIndices
6359 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6361 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6364 BOOL got_default
= FALSE
;
6368 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6369 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6372 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6374 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6379 EnterCriticalSection( &freetype_cs
);
6381 for(i
= 0; i
< count
; i
++)
6383 pgi
[i
] = get_gdi_glyph_index(physdev
->font
, lpstr
[i
]);
6388 default_char
= get_default_char_index(physdev
->font
);
6391 pgi
[i
] = default_char
;
6394 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6396 LeaveCriticalSection( &freetype_cs
);
6400 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6402 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6403 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6406 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6408 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6409 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6412 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
6416 len
= pFT_Vector_Length(vec
);
6418 out
.x
= (vec
->x
<< 6) / len
;
6419 out
.y
= (vec
->y
<< 6) / len
;
6426 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
6432 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
6434 if(!pFT_Outline_Embolden
)
6437 strength
= MulDiv(ppem
, 1 << 6, 24);
6438 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
6440 TRACE("FT_Ouline_Embolden returns %d\n", err
);
6444 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
6445 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
6446 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
6447 metrics
->horiBearingX
= bbox
.xMin
;
6448 metrics
->horiBearingY
= bbox
.yMax
;
6449 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
6450 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
6454 static inline BYTE
get_max_level( UINT format
)
6458 case GGO_GRAY2_BITMAP
: return 4;
6459 case GGO_GRAY4_BITMAP
: return 16;
6460 case GGO_GRAY8_BITMAP
: return 64;
6465 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
6467 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6469 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[uchar
>> 8]+((uchar
>> 4) & 0x0f)]+ (uchar
& 0xf)];
6471 /* We only reach this code if typographical substitution did not occur */
6472 /* Type: U or Type: Tu */
6473 return (orientation
== 1 || orientation
== 3);
6476 static FT_Vector
get_advance_metric(GdiFont
*incoming_font
, GdiFont
*font
,
6477 const FT_Glyph_Metrics
*metrics
,
6478 const FT_Matrix
*transMat
, BOOL vertical_metrics
)
6481 FT_Fixed base_advance
, em_scale
= 0;
6482 BOOL fixed_pitch_full
= FALSE
;
6484 if (vertical_metrics
)
6485 base_advance
= metrics
->vertAdvance
;
6487 base_advance
= metrics
->horiAdvance
;
6489 adv
.x
= base_advance
;
6492 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6493 they have double halfwidth character width. E.g. if the font is 19 ppem,
6494 we return 20 (not 19) for fullwidth characters as we return 10 for
6495 halfwidth characters. */
6496 if(FT_IS_SCALABLE(incoming_font
->ft_face
) &&
6497 (incoming_font
->potm
|| get_outline_text_metrics(incoming_font
)) &&
6498 !(incoming_font
->potm
->otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6500 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16,
6501 incoming_font
->ft_face
->units_per_EM
);
6502 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6503 fixed_pitch_full
= (avg_advance
> 0 &&
6504 (base_advance
+ 63) >> 6 ==
6505 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
6506 if (fixed_pitch_full
&& !transMat
)
6507 adv
.x
= (avg_advance
* 2) << 6;
6511 pFT_Vector_Transform(&adv
, transMat
);
6512 if (fixed_pitch_full
&& adv
.y
== 0) {
6514 vec
.x
= incoming_font
->ntmAvgWidth
;
6516 pFT_Vector_Transform(&vec
, transMat
);
6517 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
6521 if (font
->fake_bold
) {
6525 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
6526 pFT_Vector_Transform(&vec
, transMat
);
6527 fake_bold_adv
= normalize_vector(&vec
);
6528 adv
.x
+= fake_bold_adv
.x
;
6529 adv
.y
+= fake_bold_adv
.y
;
6533 adv
.x
= (adv
.x
+ 63) & -64;
6534 adv
.y
= -((adv
.y
+ 63) & -64);
6538 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6540 TTPOLYGONHEADER
*pph
;
6542 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
6543 unsigned int pph_start
, cpfx
;
6546 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6548 /* Ignore contours containing one point */
6549 if (point
== outline
->contours
[contour
])
6556 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6560 pph
->dwType
= TT_POLYGON_TYPE
;
6561 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6563 needed
+= sizeof(*pph
);
6565 while (point
<= outline
->contours
[contour
])
6567 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6568 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6569 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6574 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6577 } while (point
<= outline
->contours
[contour
] &&
6578 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6579 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6580 /* At the end of a contour Windows adds the start point, but
6582 if (point
> outline
->contours
[contour
] &&
6583 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6586 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6589 else if (point
<= outline
->contours
[contour
] &&
6590 outline
->tags
[point
] & FT_Curve_Tag_On
)
6592 /* add closing pt for bezier */
6594 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6603 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6606 pph
->cb
= needed
- pph_start
;
6611 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6613 /* Convert the quadratic Beziers to cubic Beziers.
6614 The parametric eqn for a cubic Bezier is, from PLRM:
6615 r(t) = at^3 + bt^2 + ct + r0
6616 with the control points:
6621 A quadratic Bezier has the form:
6622 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6624 So equating powers of t leads to:
6625 r1 = 2/3 p1 + 1/3 p0
6626 r2 = 2/3 p1 + 1/3 p2
6627 and of course r0 = p0, r3 = p2
6629 int contour
, point
= 0, first_pt
;
6630 TTPOLYGONHEADER
*pph
;
6632 DWORD pph_start
, cpfx
, type
;
6633 FT_Vector cubic_control
[4];
6634 unsigned int needed
= 0;
6636 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6639 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6643 pph
->dwType
= TT_POLYGON_TYPE
;
6644 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6646 needed
+= sizeof(*pph
);
6648 while (point
<= outline
->contours
[contour
])
6650 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6651 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6652 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6656 if (type
== TT_PRIM_LINE
)
6659 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6665 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6668 /* FIXME: Possible optimization in endpoint calculation
6669 if there are two consecutive curves */
6670 cubic_control
[0] = outline
->points
[point
-1];
6671 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6673 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6674 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6675 cubic_control
[0].x
>>= 1;
6676 cubic_control
[0].y
>>= 1;
6678 if (point
+1 > outline
->contours
[contour
])
6679 cubic_control
[3] = outline
->points
[first_pt
];
6682 cubic_control
[3] = outline
->points
[point
+1];
6683 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
6685 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6686 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6687 cubic_control
[3].x
>>= 1;
6688 cubic_control
[3].y
>>= 1;
6691 /* r1 = 1/3 p0 + 2/3 p1
6692 r2 = 1/3 p2 + 2/3 p1 */
6693 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6694 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6695 cubic_control
[2] = cubic_control
[1];
6696 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6697 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6698 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6699 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6702 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6703 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6704 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6709 } while (point
<= outline
->contours
[contour
] &&
6710 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6711 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6712 /* At the end of a contour Windows adds the start point,
6713 but only for Beziers and we've already done that.
6715 if (point
<= outline
->contours
[contour
] &&
6716 outline
->tags
[point
] & FT_Curve_Tag_On
)
6718 /* This is the closing pt of a bezier, but we've already
6719 added it, so just inc point and carry on */
6727 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6730 pph
->cb
= needed
- pph_start
;
6735 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6737 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6738 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6741 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6743 FT_Face ft_face
= incoming_font
->ft_face
;
6744 GdiFont
*font
= incoming_font
;
6745 FT_Glyph_Metrics metrics
;
6746 FT_UInt glyph_index
;
6747 DWORD width
, height
, pitch
, needed
= 0;
6748 FT_Bitmap ft_bitmap
;
6750 INT left
, right
, top
= 0, bottom
= 0;
6752 INT origin_x
= 0, origin_y
= 0;
6754 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6755 double widthRatio
= 1.0;
6756 FT_Matrix transMat
= identityMat
;
6757 FT_Matrix transMatUnrotated
;
6758 FT_Matrix transMatTategaki
;
6759 BOOL needsTransform
= FALSE
;
6760 BOOL tategaki
= (font
->name
[0] == '@');
6761 BOOL vertical_metrics
;
6762 UINT original_index
;
6764 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6765 buflen
, buf
, lpmat
);
6767 TRACE("font transform %f %f %f %f\n",
6768 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6769 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6771 if(format
& GGO_GLYPH_INDEX
) {
6772 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6773 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6774 as glyph index. "Treasure Adventure Game" depends on this. */
6775 glyph_index
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6776 TRACE("translate glyph index %04x -> %04x\n", glyph
, glyph_index
);
6778 glyph_index
= glyph
;
6779 original_index
= glyph_index
;
6780 format
&= ~GGO_GLYPH_INDEX
;
6781 /* TODO: Window also turns off tategaki for glyphs passed in by index
6782 if their unicode code points fall outside of the range that is
6786 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6787 ft_face
= font
->ft_face
;
6788 original_index
= glyph_index
;
6789 if (!vert
&& tategaki
)
6790 tategaki
= check_unicode_tategaki(glyph
);
6793 if(format
& GGO_UNHINTED
) {
6794 load_flags
|= FT_LOAD_NO_HINTING
;
6795 format
&= ~GGO_UNHINTED
;
6798 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6799 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6800 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6801 font
->gmsize
* sizeof(GM
*));
6803 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6804 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6806 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6807 *abc
= FONT_GM(font
,original_index
)->abc
;
6808 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6809 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6810 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6811 return 1; /* FIXME */
6815 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6816 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6818 /* Scaling factor */
6823 get_text_metrics(font
, &tm
);
6825 widthRatio
= (double)font
->aveWidth
;
6826 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6829 widthRatio
= font
->scale_y
;
6831 /* Scaling transform */
6832 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6835 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6838 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6840 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6841 needsTransform
= TRUE
;
6844 /* Slant transform */
6845 if (font
->fake_italic
) {
6848 slantMat
.xx
= (1 << 16);
6849 slantMat
.xy
= ((1 << 16) >> 2);
6851 slantMat
.yy
= (1 << 16);
6852 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6853 needsTransform
= TRUE
;
6856 /* Rotation transform */
6857 transMatUnrotated
= transMat
;
6858 transMatTategaki
= transMat
;
6859 if(font
->orientation
|| tategaki
) {
6860 FT_Matrix rotationMat
;
6861 FT_Matrix taterotationMat
;
6864 double orient
= font
->orientation
/ 10.0;
6865 double tate_orient
= 0.f
;
6868 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6870 tate_orient
= font
->orientation
/10.0;
6874 angle
= FT_FixedFromFloat(orient
);
6875 pFT_Vector_Unit(&vecAngle
, angle
);
6876 rotationMat
.xx
= vecAngle
.x
;
6877 rotationMat
.xy
= -vecAngle
.y
;
6878 rotationMat
.yx
= -rotationMat
.xy
;
6879 rotationMat
.yy
= rotationMat
.xx
;
6881 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6886 angle
= FT_FixedFromFloat(tate_orient
);
6887 pFT_Vector_Unit(&vecAngle
, angle
);
6888 taterotationMat
.xx
= vecAngle
.x
;
6889 taterotationMat
.xy
= -vecAngle
.y
;
6890 taterotationMat
.yx
= -taterotationMat
.xy
;
6891 taterotationMat
.yy
= taterotationMat
.xx
;
6892 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6895 needsTransform
= TRUE
;
6898 /* World transform */
6899 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6902 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6903 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6904 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6905 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6906 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6907 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6908 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6909 needsTransform
= TRUE
;
6912 /* Extra transformation specified by caller */
6913 if (!is_identity_MAT2(lpmat
))
6916 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6917 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6918 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6919 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6920 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6921 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6922 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6923 needsTransform
= TRUE
;
6926 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6927 /* there is a freetype bug where vertical metrics are only
6928 properly scaled and correct in 2.4.0 or greater */
6929 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6930 vertical_metrics
= FALSE
;
6932 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6933 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6935 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6938 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6942 metrics
= ft_face
->glyph
->metrics
;
6943 if(font
->fake_bold
) {
6944 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
6945 metrics
.width
+= 1 << 6;
6948 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6949 * by the text metrics. The proper behavior is to clip the glyph metrics to
6950 * fit within the maximums specified in the text metrics. */
6951 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6952 get_bitmap_text_metrics(incoming_font
)) {
6953 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6954 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6955 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6956 metrics
.horiBearingY
= top
;
6957 metrics
.height
= top
- bottom
;
6959 /* TODO: Are we supposed to clip the width as well...? */
6960 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6963 if(!needsTransform
) {
6964 left
= (INT
)(metrics
.horiBearingX
) & -64;
6965 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6966 top
= (metrics
.horiBearingY
+ 63) & -64;
6967 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6968 adv
= get_advance_metric(incoming_font
, font
, &metrics
, NULL
, vertical_metrics
);
6969 gm
.gmCellIncX
= adv
.x
>> 6;
6973 abc
->abcA
= origin_x
>> 6;
6974 abc
->abcB
= metrics
.width
>> 6;
6982 for(xc
= 0; xc
< 2; xc
++) {
6983 for(yc
= 0; yc
< 2; yc
++) {
6984 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6985 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6986 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6987 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6988 if(xc
== 0 && yc
== 0) {
6989 left
= right
= vec
.x
;
6990 top
= bottom
= vec
.y
;
6992 if(vec
.x
< left
) left
= vec
.x
;
6993 else if(vec
.x
> right
) right
= vec
.x
;
6994 if(vec
.y
< bottom
) bottom
= vec
.y
;
6995 else if(vec
.y
> top
) top
= vec
.y
;
7000 right
= (right
+ 63) & -64;
7001 bottom
= bottom
& -64;
7002 top
= (top
+ 63) & -64;
7004 if (tategaki
&& (font
->potm
|| get_outline_text_metrics(font
)))
7006 if (vertical_metrics
)
7007 lsb
= metrics
.horiBearingY
+ metrics
.vertBearingY
;
7009 lsb
= metrics
.vertAdvance
+ (font
->potm
->otmDescent
<< 6);
7011 vec
.y
= font
->potm
->otmDescent
<< 6;
7012 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
7013 pFT_Vector_Transform(&vec
, &transMat
);
7014 origin_x
= (vec
.x
+ left
) & -64;
7015 origin_y
= (vec
.y
+ top
+ 63) & -64;
7021 lsb
= metrics
.horiBearingX
;
7024 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
7025 adv
= get_advance_metric(incoming_font
, font
, &metrics
, &transMat
, vertical_metrics
);
7026 gm
.gmCellIncX
= adv
.x
>> 6;
7027 gm
.gmCellIncY
= adv
.y
>> 6;
7029 adv
= get_advance_metric(incoming_font
, font
, &metrics
, &transMatUnrotated
, vertical_metrics
);
7033 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
7034 abc
->abcA
= vec
.x
>> 6;
7036 vec
.x
= metrics
.width
;
7038 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
7040 abc
->abcB
= vec
.x
>> 6;
7042 abc
->abcB
= -vec
.x
>> 6;
7045 width
= (right
- left
) >> 6;
7046 height
= (top
- bottom
) >> 6;
7047 gm
.gmBlackBoxX
= width
? width
: 1;
7048 gm
.gmBlackBoxY
= height
? height
: 1;
7049 gm
.gmptGlyphOrigin
.x
= origin_x
>> 6;
7050 gm
.gmptGlyphOrigin
.y
= origin_y
>> 6;
7051 if (!abc
->abcB
) abc
->abcB
= 1;
7052 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
7054 TRACE("%u,%u,%s,%d,%d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
7055 wine_dbgstr_point(&gm
.gmptGlyphOrigin
),
7056 gm
.gmCellIncX
, gm
.gmCellIncY
);
7058 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
7059 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
7061 FONT_GM(font
,original_index
)->gm
= gm
;
7062 FONT_GM(font
,original_index
)->abc
= *abc
;
7063 FONT_GM(font
,original_index
)->init
= TRUE
;
7066 if(format
== GGO_METRICS
)
7069 return 1; /* FIXME */
7072 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
7073 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
7075 TRACE("loaded a bitmap\n");
7081 pitch
= ((width
+ 31) >> 5) << 2;
7082 needed
= pitch
* height
;
7084 if(!buf
|| !buflen
) break;
7085 if (!needed
) return GDI_ERROR
; /* empty glyph */
7086 if (needed
> buflen
)
7089 switch(ft_face
->glyph
->format
) {
7090 case ft_glyph_format_bitmap
:
7092 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
7093 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
7094 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7096 if (!font
->fake_bold
)
7097 memcpy(dst
, src
, w
);
7101 for (x
= 0; x
< w
; x
++) {
7102 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
7104 dst
[x
+1] = (src
[x
] & 0x01) << 7;
7107 src
+= ft_face
->glyph
->bitmap
.pitch
;
7113 case ft_glyph_format_outline
:
7114 ft_bitmap
.width
= width
;
7115 ft_bitmap
.rows
= height
;
7116 ft_bitmap
.pitch
= pitch
;
7117 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
7118 ft_bitmap
.buffer
= buf
;
7121 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
7123 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
7125 /* Note: FreeType will only set 'black' bits for us. */
7126 memset(buf
, 0, needed
);
7127 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
7131 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
7136 case GGO_GRAY2_BITMAP
:
7137 case GGO_GRAY4_BITMAP
:
7138 case GGO_GRAY8_BITMAP
:
7139 case WINE_GGO_GRAY16_BITMAP
:
7141 unsigned int max_level
, row
, col
;
7144 pitch
= (width
+ 3) / 4 * 4;
7145 needed
= pitch
* height
;
7147 if(!buf
|| !buflen
) break;
7148 if (!needed
) return GDI_ERROR
; /* empty glyph */
7149 if (needed
> buflen
)
7152 max_level
= get_max_level( format
);
7154 switch(ft_face
->glyph
->format
) {
7155 case ft_glyph_format_bitmap
:
7157 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
7158 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7160 memset( buf
, 0, needed
);
7162 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++) {
7163 if (src
[x
/ 8] & masks
[x
% 8]) {
7165 if (font
->fake_bold
&& x
+1 < pitch
) dst
[x
+1] = max_level
;
7168 src
+= ft_face
->glyph
->bitmap
.pitch
;
7173 case ft_glyph_format_outline
:
7175 ft_bitmap
.width
= width
;
7176 ft_bitmap
.rows
= height
;
7177 ft_bitmap
.pitch
= pitch
;
7178 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
7179 ft_bitmap
.buffer
= buf
;
7182 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
7184 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
7186 memset(ft_bitmap
.buffer
, 0, buflen
);
7188 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
7190 if (max_level
!= 255)
7192 for (row
= 0, start
= buf
; row
< height
; row
++)
7194 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
7195 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
7203 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
7209 case WINE_GGO_HRGB_BITMAP
:
7210 case WINE_GGO_HBGR_BITMAP
:
7211 case WINE_GGO_VRGB_BITMAP
:
7212 case WINE_GGO_VBGR_BITMAP
:
7213 #ifdef FT_LCD_FILTER_H
7215 switch (ft_face
->glyph
->format
)
7217 case FT_GLYPH_FORMAT_BITMAP
:
7223 needed
= pitch
* height
;
7225 if (!buf
|| !buflen
) break;
7226 if (!needed
) return GDI_ERROR
; /* empty glyph */
7227 if (needed
> buflen
)
7230 memset(buf
, 0, buflen
);
7232 src
= ft_face
->glyph
->bitmap
.buffer
;
7233 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7235 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7238 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
7240 if ( src
[x
/ 8] & masks
[x
% 8] )
7242 ((unsigned int *)dst
)[x
] = ~0u;
7243 if (font
->fake_bold
&& x
+1 < width
) ((unsigned int *)dst
)[x
+1] = ~0u;
7253 case FT_GLYPH_FORMAT_OUTLINE
:
7257 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
7258 INT x_shift
, y_shift
;
7260 FT_Render_Mode render_mode
=
7261 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
7262 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
7264 if (!width
|| !height
)
7266 if (!buf
|| !buflen
) break;
7270 if ( render_mode
== FT_RENDER_MODE_LCD
)
7272 gm
.gmBlackBoxX
+= 2;
7273 gm
.gmptGlyphOrigin
.x
-= 1;
7278 gm
.gmBlackBoxY
+= 2;
7279 gm
.gmptGlyphOrigin
.y
+= 1;
7283 width
= gm
.gmBlackBoxX
;
7284 height
= gm
.gmBlackBoxY
;
7286 needed
= pitch
* height
;
7288 if (!buf
|| !buflen
) break;
7289 if (needed
> buflen
)
7292 memset(buf
, 0, buflen
);
7294 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
7296 if ( needsTransform
)
7297 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
7299 if ( pFT_Library_SetLcdFilter
)
7300 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
7301 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
7303 src
= ft_face
->glyph
->bitmap
.buffer
;
7304 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7305 src_width
= ft_face
->glyph
->bitmap
.width
;
7306 src_height
= ft_face
->glyph
->bitmap
.rows
;
7308 if ( render_mode
== FT_RENDER_MODE_LCD
)
7316 rgb_interval
= src_pitch
;
7321 x_shift
= ft_face
->glyph
->bitmap_left
- (left
>> 6);
7324 src
+= hmul
* -x_shift
;
7325 src_width
-= hmul
* -x_shift
;
7327 else if ( x_shift
> 0 )
7333 y_shift
= (top
>> 6) - ft_face
->glyph
->bitmap_top
;
7336 src
+= src_pitch
* vmul
* -y_shift
;
7337 src_height
-= vmul
* -y_shift
;
7339 else if ( y_shift
> 0 )
7341 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
7345 width
= min( width
, src_width
/ hmul
);
7346 height
= min( height
, src_height
/ vmul
);
7350 for ( x
= 0; x
< width
; x
++ )
7354 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
7355 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7356 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
7357 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7361 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
7362 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7363 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
7364 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7367 src
+= src_pitch
* vmul
;
7368 dst
+= pitch
/ sizeof(*dst
);
7375 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
7387 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7389 if(buflen
== 0) buf
= NULL
;
7391 if (needsTransform
&& buf
)
7392 pFT_Outline_Transform(outline
, &transMatTategaki
);
7394 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
7396 if (!buf
|| !buflen
)
7398 if (needed
> buflen
)
7401 get_native_glyph_outline(outline
, buflen
, buf
);
7406 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7407 if(buflen
== 0) buf
= NULL
;
7409 if (needsTransform
&& buf
)
7410 pFT_Outline_Transform(outline
, &transMat
);
7412 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
7414 if (!buf
|| !buflen
)
7416 if (needed
> buflen
)
7419 get_bezier_glyph_outline(outline
, buflen
, buf
);
7424 FIXME("Unsupported format %d\n", format
);
7431 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7433 FT_Face ft_face
= font
->ft_face
;
7434 FT_WinFNT_HeaderRec winfnt_header
;
7435 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7436 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7437 font
->potm
->otmSize
= size
;
7439 #define TM font->potm->otmTextMetrics
7440 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7442 TM
.tmHeight
= winfnt_header
.pixel_height
;
7443 TM
.tmAscent
= winfnt_header
.ascent
;
7444 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7445 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7446 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7447 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7448 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7449 TM
.tmWeight
= winfnt_header
.weight
;
7451 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7452 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7453 TM
.tmFirstChar
= winfnt_header
.first_char
;
7454 TM
.tmLastChar
= winfnt_header
.last_char
;
7455 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7456 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7457 TM
.tmItalic
= winfnt_header
.italic
;
7458 TM
.tmUnderlined
= font
->underline
;
7459 TM
.tmStruckOut
= font
->strikeout
;
7460 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7461 TM
.tmCharSet
= winfnt_header
.charset
;
7465 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7466 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7467 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7468 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7469 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7470 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7471 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7472 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7474 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7475 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7477 TM
.tmLastChar
= 255;
7478 TM
.tmDefaultChar
= 32;
7479 TM
.tmBreakChar
= 32;
7480 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7481 TM
.tmUnderlined
= font
->underline
;
7482 TM
.tmStruckOut
= font
->strikeout
;
7483 /* NB inverted meaning of TMPF_FIXED_PITCH */
7484 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
7485 TM
.tmCharSet
= font
->charset
;
7493 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7495 double scale_x
, scale_y
;
7499 scale_x
= (double)font
->aveWidth
;
7500 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7503 scale_x
= font
->scale_y
;
7505 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7506 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7508 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7509 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7511 SCALE_Y(ptm
->tmHeight
);
7512 SCALE_Y(ptm
->tmAscent
);
7513 SCALE_Y(ptm
->tmDescent
);
7514 SCALE_Y(ptm
->tmInternalLeading
);
7515 SCALE_Y(ptm
->tmExternalLeading
);
7516 SCALE_Y(ptm
->tmOverhang
);
7518 SCALE_X(ptm
->tmAveCharWidth
);
7519 SCALE_X(ptm
->tmMaxCharWidth
);
7525 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7527 double scale_x
, scale_y
;
7531 scale_x
= (double)font
->aveWidth
;
7532 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7535 scale_x
= font
->scale_y
;
7537 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7538 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7540 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7542 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7543 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7545 SCALE_Y(potm
->otmAscent
);
7546 SCALE_Y(potm
->otmDescent
);
7547 SCALE_Y(potm
->otmLineGap
);
7548 SCALE_Y(potm
->otmsCapEmHeight
);
7549 SCALE_Y(potm
->otmsXHeight
);
7550 SCALE_Y(potm
->otmrcFontBox
.top
);
7551 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7552 SCALE_X(potm
->otmrcFontBox
.left
);
7553 SCALE_X(potm
->otmrcFontBox
.right
);
7554 SCALE_Y(potm
->otmMacAscent
);
7555 SCALE_Y(potm
->otmMacDescent
);
7556 SCALE_Y(potm
->otmMacLineGap
);
7557 SCALE_X(potm
->otmptSubscriptSize
.x
);
7558 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7559 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7560 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7561 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7562 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7563 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7564 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7565 SCALE_Y(potm
->otmsStrikeoutSize
);
7566 SCALE_Y(potm
->otmsStrikeoutPosition
);
7567 SCALE_Y(potm
->otmsUnderscoreSize
);
7568 SCALE_Y(potm
->otmsUnderscorePosition
);
7574 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7578 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7580 /* Make sure that the font has sane width/height ratio */
7583 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7585 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7590 *ptm
= font
->potm
->otmTextMetrics
;
7591 scale_font_metrics(font
, ptm
);
7595 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7599 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7601 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7607 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7610 FT_Face ft_face
= font
->ft_face
;
7611 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7613 TT_HoriHeader
*pHori
;
7614 TT_Postscript
*pPost
;
7616 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7618 INT ascent
, descent
;
7621 TRACE("font=%p\n", font
);
7623 if(!FT_IS_SCALABLE(ft_face
))
7626 needed
= sizeof(*font
->potm
);
7628 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7629 family_nameW
= strdupW(font
->name
);
7631 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7634 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7635 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7637 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7639 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7642 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7643 face_nameW
= strdupW(font
->name
);
7645 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7646 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7648 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7651 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7652 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7653 full_nameW
= strdupW(fake_nameW
);
7655 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7657 /* These names should be read from the TT name table */
7659 /* length of otmpFamilyName */
7662 /* length of otmpFaceName */
7665 /* length of otmpStyleName */
7668 /* length of otmpFullName */
7672 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7674 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7676 FIXME("Can't find OS/2 table - not TT font?\n");
7680 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7682 FIXME("Can't find HHEA table - not TT font?\n");
7686 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7688 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",
7689 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7690 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7691 pOS2
->xAvgCharWidth
,
7692 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7693 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7694 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7696 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7697 font
->potm
->otmSize
= needed
;
7699 #define TM font->potm->otmTextMetrics
7701 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
7702 if(pOS2
->usWinAscent
+ windescent
== 0) {
7703 ascent
= pHori
->Ascender
;
7704 descent
= -pHori
->Descender
;
7706 ascent
= pOS2
->usWinAscent
;
7707 descent
= windescent
;
7710 font
->ntmCellHeight
= ascent
+ descent
;
7711 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7713 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7714 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7717 TM
.tmAscent
= font
->yMax
;
7718 TM
.tmDescent
= -font
->yMin
;
7719 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7721 TM
.tmAscent
= SCALE_Y(ascent
);
7722 TM
.tmDescent
= SCALE_Y(descent
);
7723 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7726 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7729 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7731 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7732 ((ascent
+ descent
) -
7733 (pHori
->Ascender
- pHori
->Descender
))));
7735 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7736 if (TM
.tmAveCharWidth
== 0) {
7737 TM
.tmAveCharWidth
= 1;
7739 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7740 TM
.tmWeight
= FW_REGULAR
;
7741 if (font
->fake_bold
) {
7742 TM
.tmAveCharWidth
++;
7743 TM
.tmMaxCharWidth
++;
7744 TM
.tmWeight
= FW_BOLD
;
7748 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7750 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7751 TM
.tmWeight
= pOS2
->usWeightClass
;
7753 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7754 TM
.tmWeight
= pOS2
->usWeightClass
;
7757 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7758 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7759 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7760 * symbol range to 0 - f0ff
7763 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7768 case 1255: /* Hebrew */
7769 TM
.tmLastChar
= 0xf896;
7771 case 1257: /* Baltic */
7772 TM
.tmLastChar
= 0xf8fd;
7775 TM
.tmLastChar
= 0xf0ff;
7777 TM
.tmBreakChar
= 0x20;
7778 TM
.tmDefaultChar
= 0x1f;
7782 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7783 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7785 if(pOS2
->usFirstCharIndex
<= 1)
7786 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7787 else if (pOS2
->usFirstCharIndex
> 0xff)
7788 TM
.tmBreakChar
= 0x20;
7790 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7791 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7793 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7794 TM
.tmUnderlined
= font
->underline
;
7795 TM
.tmStruckOut
= font
->strikeout
;
7797 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7798 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7799 (pOS2
->version
== 0xFFFFU
||
7800 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7801 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7803 TM
.tmPitchAndFamily
= 0;
7805 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7807 case PAN_FAMILY_SCRIPT
:
7808 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7811 case PAN_FAMILY_DECORATIVE
:
7812 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7817 case PAN_FAMILY_TEXT_DISPLAY
:
7818 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7819 /* which is clearly not what the panose spec says. */
7821 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7822 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7823 TM
.tmPitchAndFamily
= FF_MODERN
;
7826 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7831 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7834 case PAN_SERIF_COVE
:
7835 case PAN_SERIF_OBTUSE_COVE
:
7836 case PAN_SERIF_SQUARE_COVE
:
7837 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7838 case PAN_SERIF_SQUARE
:
7839 case PAN_SERIF_THIN
:
7840 case PAN_SERIF_BONE
:
7841 case PAN_SERIF_EXAGGERATED
:
7842 case PAN_SERIF_TRIANGLE
:
7843 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7846 case PAN_SERIF_NORMAL_SANS
:
7847 case PAN_SERIF_OBTUSE_SANS
:
7848 case PAN_SERIF_PERP_SANS
:
7849 case PAN_SERIF_FLARED
:
7850 case PAN_SERIF_ROUNDED
:
7851 TM
.tmPitchAndFamily
|= FF_SWISS
;
7858 if(FT_IS_SCALABLE(ft_face
))
7859 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7861 if(FT_IS_SFNT(ft_face
))
7863 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7864 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7866 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7869 TM
.tmCharSet
= font
->charset
;
7871 font
->potm
->otmFiller
= 0;
7872 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7873 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7874 if (font
->fake_italic
)
7875 font
->potm
->otmfsSelection
|= 1;
7876 if (font
->fake_bold
)
7877 font
->potm
->otmfsSelection
|= 1 << 5;
7878 font
->potm
->otmfsType
= pOS2
->fsType
;
7879 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7880 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7881 font
->potm
->otmItalicAngle
= 0; /* POST table */
7882 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7883 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7884 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7885 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7886 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7887 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7888 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7889 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7890 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7891 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7892 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7893 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7894 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7895 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7896 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7897 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7898 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7899 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7900 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7901 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7902 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7903 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7904 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7905 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7907 font
->potm
->otmsUnderscoreSize
= 0;
7908 font
->potm
->otmsUnderscorePosition
= 0;
7910 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7911 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7917 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7918 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7919 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7920 strcpyW((WCHAR
*)cp
, family_nameW
);
7922 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7923 strcpyW((WCHAR
*)cp
, style_nameW
);
7925 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7926 strcpyW((WCHAR
*)cp
, face_nameW
);
7928 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7929 strcpyW((WCHAR
*)cp
, full_nameW
);
7933 HeapFree(GetProcessHeap(), 0, style_nameW
);
7934 HeapFree(GetProcessHeap(), 0, family_nameW
);
7935 HeapFree(GetProcessHeap(), 0, face_nameW
);
7936 HeapFree(GetProcessHeap(), 0, full_nameW
);
7940 /*************************************************************
7941 * freetype_GetGlyphOutline
7943 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7944 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7946 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7952 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7953 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7957 EnterCriticalSection( &freetype_cs
);
7958 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7959 LeaveCriticalSection( &freetype_cs
);
7963 /*************************************************************
7964 * freetype_GetTextMetrics
7966 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7968 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7973 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7974 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7978 EnterCriticalSection( &freetype_cs
);
7979 ret
= get_text_metrics( physdev
->font
, metrics
);
7980 LeaveCriticalSection( &freetype_cs
);
7984 /*************************************************************
7985 * freetype_GetOutlineTextMetrics
7987 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7989 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7994 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7995 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7998 TRACE("font=%p\n", physdev
->font
);
8000 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
8003 EnterCriticalSection( &freetype_cs
);
8005 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
8007 if(potm
&& cbSize
>= physdev
->font
->potm
->otmSize
)
8009 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
8010 scale_outline_font_metrics(physdev
->font
, potm
);
8012 ret
= physdev
->font
->potm
->otmSize
;
8014 LeaveCriticalSection( &freetype_cs
);
8018 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
8020 child
->font
= alloc_font();
8021 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
8022 if(!child
->font
->ft_face
)
8024 free_font(child
->font
);
8029 child
->font
->font_desc
= font
->font_desc
;
8030 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
8031 child
->font
->orientation
= font
->orientation
;
8032 child
->font
->scale_y
= font
->scale_y
;
8033 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
8034 child
->font
->base_font
= font
;
8035 TRACE("created child font %p for base %p\n", child
->font
, font
);
8039 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
8042 CHILD_FONT
*child_font
;
8045 font
= font
->base_font
;
8047 *linked_font
= font
;
8049 if((*glyph
= get_glyph_index(font
, c
)))
8052 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
8053 *vert
= (o
!= *glyph
);
8057 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
8059 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
8061 if(!child_font
->font
)
8062 if(!load_child_font(font
, child_font
))
8065 if(!child_font
->font
->ft_face
)
8067 g
= get_glyph_index(child_font
->font
, c
);
8069 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
8073 *linked_font
= child_font
->font
;
8084 /*************************************************************
8085 * freetype_GetCharWidth
8087 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
8089 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8093 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8097 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
8098 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
8101 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
8104 EnterCriticalSection( &freetype_cs
);
8105 for(c
= firstChar
; c
<= lastChar
; c
++) {
8106 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
8107 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8109 LeaveCriticalSection( &freetype_cs
);
8113 /*************************************************************
8114 * freetype_GetCharABCWidths
8116 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
8118 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8121 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8125 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
8126 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
8129 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
8132 EnterCriticalSection( &freetype_cs
);
8134 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
8135 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
8137 LeaveCriticalSection( &freetype_cs
);
8141 /*************************************************************
8142 * freetype_GetCharABCWidthsI
8144 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
8146 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8149 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8153 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
8154 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
8157 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
8161 EnterCriticalSection( &freetype_cs
);
8163 for(c
= 0; c
< count
; c
++, buffer
++)
8164 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
8165 &gm
, buffer
, 0, NULL
, &identity
);
8167 LeaveCriticalSection( &freetype_cs
);
8171 /*************************************************************
8172 * freetype_GetTextExtentExPoint
8174 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
8176 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8180 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8184 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
8185 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
8188 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
8191 EnterCriticalSection( &freetype_cs
);
8193 for (idx
= pos
= 0; idx
< count
; idx
++)
8195 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
8196 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8200 LeaveCriticalSection( &freetype_cs
);
8204 /*************************************************************
8205 * freetype_GetTextExtentExPointI
8207 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
8209 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8213 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8217 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
8218 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
8221 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
8224 EnterCriticalSection( &freetype_cs
);
8226 for (idx
= pos
= 0; idx
< count
; idx
++)
8228 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
8229 &gm
, &abc
, 0, NULL
, &identity
);
8230 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8234 LeaveCriticalSection( &freetype_cs
);
8238 /*************************************************************
8239 * freetype_GetFontData
8241 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
8243 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8247 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
8248 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
8251 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
8252 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
8253 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
8255 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
8258 /*************************************************************
8259 * freetype_GetTextFace
8261 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
8264 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8268 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
8269 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
8272 n
= strlenW(physdev
->font
->name
) + 1;
8275 lstrcpynW(str
, physdev
->font
->name
, count
);
8281 /*************************************************************
8282 * freetype_GetTextCharsetInfo
8284 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
8286 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8290 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
8291 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
8293 if (fs
) *fs
= physdev
->font
->fs
;
8294 return physdev
->font
->charset
;
8297 /* Retrieve a list of supported Unicode ranges for a given font.
8298 * Can be called with NULL gs to calculate the buffer size. Returns
8299 * the number of ranges found.
8301 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
8303 DWORD num_ranges
= 0;
8305 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8308 FT_ULong char_code
, char_code_prev
;
8311 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
8313 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8314 face
->num_glyphs
, glyph_code
, char_code
);
8316 if (!glyph_code
) return 0;
8320 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
8321 gs
->ranges
[0].cGlyphs
= 0;
8322 gs
->cGlyphsSupported
= 0;
8328 if (char_code
< char_code_prev
)
8330 ERR("expected increasing char code from FT_Get_Next_Char\n");
8333 if (char_code
- char_code_prev
> 1)
8338 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
8339 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
8340 gs
->cGlyphsSupported
++;
8345 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
8346 gs
->cGlyphsSupported
++;
8348 char_code_prev
= char_code
;
8349 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
8353 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
8358 /*************************************************************
8359 * freetype_GetFontUnicodeRanges
8361 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
8363 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8364 DWORD size
, num_ranges
;
8368 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
8369 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
8372 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
8373 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
8376 glyphset
->cbThis
= size
;
8377 glyphset
->cRanges
= num_ranges
;
8378 glyphset
->flAccel
= 0;
8383 /*************************************************************
8384 * freetype_FontIsLinked
8386 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
8388 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8393 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
8394 return dev
->funcs
->pFontIsLinked( dev
);
8398 EnterCriticalSection( &freetype_cs
);
8399 ret
= !list_empty(&physdev
->font
->child_fonts
);
8400 LeaveCriticalSection( &freetype_cs
);
8404 /*************************************************************************
8405 * GetRasterizerCaps (GDI32.@)
8407 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8409 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8410 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
8411 lprs
->nLanguageID
= 0;
8415 /*************************************************************
8416 * freetype_GetFontRealizationInfo
8418 static BOOL
freetype_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
8420 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8421 struct font_realization_info
*info
= ptr
;
8425 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
8426 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
8429 TRACE("(%p, %p)\n", physdev
->font
, info
);
8432 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8435 info
->cache_num
= physdev
->font
->cache_num
;
8436 info
->instance_id
= physdev
->font
->instance_id
;
8437 if (info
->size
== sizeof(*info
))
8440 info
->face_index
= physdev
->font
->ft_face
->face_index
;
8441 info
->simulations
= 0;
8442 if (physdev
->font
->fake_bold
)
8443 info
->simulations
|= 0x1;
8444 if (physdev
->font
->fake_italic
)
8445 info
->simulations
|= 0x2;
8451 /*************************************************************************
8452 * GetFontFileInfo (GDI32.@)
8454 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
, DWORD size
, DWORD
*needed
)
8456 struct font_handle_entry
*entry
= handle_entry( instance_id
);
8457 const GdiFont
*font
;
8461 SetLastError(ERROR_INVALID_PARAMETER
);
8466 *needed
= sizeof(*info
) + strlenW(font
->fileinfo
->path
) * sizeof(WCHAR
);
8469 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
8473 /* path is included too */
8474 memcpy(info
, font
->fileinfo
, *needed
);
8478 /*************************************************************************
8479 * Kerning support for TrueType fonts
8481 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8483 struct TT_kern_table
8489 struct TT_kern_subtable
8498 USHORT horizontal
: 1;
8500 USHORT cross_stream
: 1;
8501 USHORT override
: 1;
8502 USHORT reserved1
: 4;
8508 struct TT_format0_kern_subtable
8512 USHORT entrySelector
;
8523 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8524 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8525 const USHORT
*glyph_to_char
,
8526 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8529 const struct TT_kern_pair
*tt_kern_pair
;
8531 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8533 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8535 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8536 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8537 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8539 if (!kern_pair
|| !cPairs
)
8542 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8544 nPairs
= min(nPairs
, cPairs
);
8546 for (i
= 0; i
< nPairs
; i
++)
8548 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8549 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8550 /* this algorithm appears to better match what Windows does */
8551 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8552 if (kern_pair
->iKernAmount
< 0)
8554 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8555 kern_pair
->iKernAmount
-= font
->ppem
;
8557 else if (kern_pair
->iKernAmount
> 0)
8559 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8560 kern_pair
->iKernAmount
+= font
->ppem
;
8562 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8564 TRACE("left %u right %u value %d\n",
8565 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8569 TRACE("copied %u entries\n", nPairs
);
8573 /*************************************************************
8574 * freetype_GetKerningPairs
8576 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8580 const struct TT_kern_table
*tt_kern_table
;
8581 const struct TT_kern_subtable
*tt_kern_subtable
;
8583 USHORT
*glyph_to_char
;
8585 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8587 if (!(font
= physdev
->font
))
8589 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8590 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8594 EnterCriticalSection( &freetype_cs
);
8595 if (font
->total_kern_pairs
!= (DWORD
)-1)
8597 if (cPairs
&& kern_pair
)
8599 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8600 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8602 else cPairs
= font
->total_kern_pairs
;
8604 LeaveCriticalSection( &freetype_cs
);
8608 font
->total_kern_pairs
= 0;
8610 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8612 if (length
== GDI_ERROR
)
8614 TRACE("no kerning data in the font\n");
8615 LeaveCriticalSection( &freetype_cs
);
8619 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8622 WARN("Out of memory\n");
8623 LeaveCriticalSection( &freetype_cs
);
8627 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8629 /* build a glyph index to char code map */
8630 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8633 WARN("Out of memory allocating a glyph index to char code map\n");
8634 HeapFree(GetProcessHeap(), 0, buf
);
8635 LeaveCriticalSection( &freetype_cs
);
8639 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8645 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8647 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8648 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8652 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8654 /* FIXME: This doesn't match what Windows does: it does some fancy
8655 * things with duplicate glyph index to char code mappings, while
8656 * we just avoid overriding existing entries.
8658 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8659 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8661 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8668 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8669 for (n
= 0; n
<= 65535; n
++)
8670 glyph_to_char
[n
] = (USHORT
)n
;
8673 tt_kern_table
= buf
;
8674 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8675 TRACE("version %u, nTables %u\n",
8676 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8678 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8680 for (i
= 0; i
< nTables
; i
++)
8682 struct TT_kern_subtable tt_kern_subtable_copy
;
8684 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8685 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8686 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8688 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8689 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8690 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8692 /* According to the TrueType specification this is the only format
8693 * that will be properly interpreted by Windows and OS/2
8695 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8697 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8699 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8700 glyph_to_char
, NULL
, 0);
8701 font
->total_kern_pairs
+= new_chunk
;
8703 if (!font
->kern_pairs
)
8704 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8705 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8707 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8708 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8710 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8711 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8714 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8716 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8719 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8720 HeapFree(GetProcessHeap(), 0, buf
);
8722 if (cPairs
&& kern_pair
)
8724 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8725 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8727 else cPairs
= font
->total_kern_pairs
;
8729 LeaveCriticalSection( &freetype_cs
);
8733 static const struct gdi_dc_funcs freetype_funcs
=
8735 NULL
, /* pAbortDoc */
8736 NULL
, /* pAbortPath */
8737 NULL
, /* pAlphaBlend */
8738 NULL
, /* pAngleArc */
8741 NULL
, /* pBeginPath */
8742 NULL
, /* pBlendImage */
8744 NULL
, /* pCloseFigure */
8745 NULL
, /* pCreateCompatibleDC */
8746 freetype_CreateDC
, /* pCreateDC */
8747 freetype_DeleteDC
, /* pDeleteDC */
8748 NULL
, /* pDeleteObject */
8749 NULL
, /* pDeviceCapabilities */
8750 NULL
, /* pEllipse */
8752 NULL
, /* pEndPage */
8753 NULL
, /* pEndPath */
8754 freetype_EnumFonts
, /* pEnumFonts */
8755 NULL
, /* pEnumICMProfiles */
8756 NULL
, /* pExcludeClipRect */
8757 NULL
, /* pExtDeviceMode */
8758 NULL
, /* pExtEscape */
8759 NULL
, /* pExtFloodFill */
8760 NULL
, /* pExtSelectClipRgn */
8761 NULL
, /* pExtTextOut */
8762 NULL
, /* pFillPath */
8763 NULL
, /* pFillRgn */
8764 NULL
, /* pFlattenPath */
8765 freetype_FontIsLinked
, /* pFontIsLinked */
8766 NULL
, /* pFrameRgn */
8767 NULL
, /* pGdiComment */
8768 NULL
, /* pGetBoundsRect */
8769 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8770 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8771 freetype_GetCharWidth
, /* pGetCharWidth */
8772 NULL
, /* pGetDeviceCaps */
8773 NULL
, /* pGetDeviceGammaRamp */
8774 freetype_GetFontData
, /* pGetFontData */
8775 freetype_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
8776 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8777 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8778 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8779 NULL
, /* pGetICMProfile */
8780 NULL
, /* pGetImage */
8781 freetype_GetKerningPairs
, /* pGetKerningPairs */
8782 NULL
, /* pGetNearestColor */
8783 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8784 NULL
, /* pGetPixel */
8785 NULL
, /* pGetSystemPaletteEntries */
8786 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8787 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8788 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8789 freetype_GetTextFace
, /* pGetTextFace */
8790 freetype_GetTextMetrics
, /* pGetTextMetrics */
8791 NULL
, /* pGradientFill */
8792 NULL
, /* pIntersectClipRect */
8793 NULL
, /* pInvertRgn */
8795 NULL
, /* pModifyWorldTransform */
8797 NULL
, /* pOffsetClipRgn */
8798 NULL
, /* pOffsetViewportOrg */
8799 NULL
, /* pOffsetWindowOrg */
8800 NULL
, /* pPaintRgn */
8803 NULL
, /* pPolyBezier */
8804 NULL
, /* pPolyBezierTo */
8805 NULL
, /* pPolyDraw */
8806 NULL
, /* pPolyPolygon */
8807 NULL
, /* pPolyPolyline */
8808 NULL
, /* pPolygon */
8809 NULL
, /* pPolyline */
8810 NULL
, /* pPolylineTo */
8811 NULL
, /* pPutImage */
8812 NULL
, /* pRealizeDefaultPalette */
8813 NULL
, /* pRealizePalette */
8814 NULL
, /* pRectangle */
8815 NULL
, /* pResetDC */
8816 NULL
, /* pRestoreDC */
8817 NULL
, /* pRoundRect */
8819 NULL
, /* pScaleViewportExt */
8820 NULL
, /* pScaleWindowExt */
8821 NULL
, /* pSelectBitmap */
8822 NULL
, /* pSelectBrush */
8823 NULL
, /* pSelectClipPath */
8824 freetype_SelectFont
, /* pSelectFont */
8825 NULL
, /* pSelectPalette */
8826 NULL
, /* pSelectPen */
8827 NULL
, /* pSetArcDirection */
8828 NULL
, /* pSetBkColor */
8829 NULL
, /* pSetBkMode */
8830 NULL
, /* pSetDCBrushColor */
8831 NULL
, /* pSetDCPenColor */
8832 NULL
, /* pSetDIBColorTable */
8833 NULL
, /* pSetDIBitsToDevice */
8834 NULL
, /* pSetDeviceClipping */
8835 NULL
, /* pSetDeviceGammaRamp */
8836 NULL
, /* pSetLayout */
8837 NULL
, /* pSetMapMode */
8838 NULL
, /* pSetMapperFlags */
8839 NULL
, /* pSetPixel */
8840 NULL
, /* pSetPolyFillMode */
8841 NULL
, /* pSetROP2 */
8842 NULL
, /* pSetRelAbs */
8843 NULL
, /* pSetStretchBltMode */
8844 NULL
, /* pSetTextAlign */
8845 NULL
, /* pSetTextCharacterExtra */
8846 NULL
, /* pSetTextColor */
8847 NULL
, /* pSetTextJustification */
8848 NULL
, /* pSetViewportExt */
8849 NULL
, /* pSetViewportOrg */
8850 NULL
, /* pSetWindowExt */
8851 NULL
, /* pSetWindowOrg */
8852 NULL
, /* pSetWorldTransform */
8853 NULL
, /* pStartDoc */
8854 NULL
, /* pStartPage */
8855 NULL
, /* pStretchBlt */
8856 NULL
, /* pStretchDIBits */
8857 NULL
, /* pStrokeAndFillPath */
8858 NULL
, /* pStrokePath */
8859 NULL
, /* pUnrealizePalette */
8860 NULL
, /* pWidenPath */
8861 NULL
, /* wine_get_wgl_driver */
8862 GDI_PRIORITY_FONT_DRV
/* priority */
8865 #else /* HAVE_FREETYPE */
8867 struct font_fileinfo
;
8869 /*************************************************************************/
8871 BOOL
WineEngInit(void)
8876 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8878 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8882 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8884 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8888 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8890 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8894 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8895 LPCWSTR font_file
, LPCWSTR font_path
)
8901 /*************************************************************************
8902 * GetRasterizerCaps (GDI32.@)
8904 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8906 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8908 lprs
->nLanguageID
= 0;
8912 /*************************************************************************
8913 * GetFontFileInfo (GDI32.@)
8915 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
, DWORD size
, DWORD
*needed
)
8921 #endif /* HAVE_FREETYPE */