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_Set_Charmap
);
163 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
164 MAKE_FUNCPTR(FT_Vector_Length
);
165 MAKE_FUNCPTR(FT_Vector_Transform
);
166 MAKE_FUNCPTR(FT_Vector_Unit
);
167 static FT_Error (*pFT_Outline_Embolden
)(FT_Outline
*, FT_Pos
);
168 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
169 #ifdef FT_LCD_FILTER_H
170 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute
);
176 MAKE_FUNCPTR(FcFontList
);
177 MAKE_FUNCPTR(FcFontSetDestroy
);
178 MAKE_FUNCPTR(FcInit
);
179 MAKE_FUNCPTR(FcObjectSetAdd
);
180 MAKE_FUNCPTR(FcObjectSetCreate
);
181 MAKE_FUNCPTR(FcObjectSetDestroy
);
182 MAKE_FUNCPTR(FcPatternCreate
);
183 MAKE_FUNCPTR(FcPatternDestroy
);
184 MAKE_FUNCPTR(FcPatternGetBool
);
185 MAKE_FUNCPTR(FcPatternGetInteger
);
186 MAKE_FUNCPTR(FcPatternGetString
);
192 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
193 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
194 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
197 #ifndef ft_encoding_none
198 #define FT_ENCODING_NONE ft_encoding_none
200 #ifndef ft_encoding_ms_symbol
201 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
203 #ifndef ft_encoding_unicode
204 #define FT_ENCODING_UNICODE ft_encoding_unicode
206 #ifndef ft_encoding_apple_roman
207 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
210 #ifdef WORDS_BIGENDIAN
211 #define GET_BE_WORD(x) (x)
212 #define GET_BE_DWORD(x) (x)
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
215 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
218 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
219 ( ( (FT_ULong)_x4 << 24 ) | \
220 ( (FT_ULong)_x3 << 16 ) | \
221 ( (FT_ULong)_x2 << 8 ) | \
224 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
225 #define MS_GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
226 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
227 #define MS_TTCF_TAG MS_MAKE_TAG('t', 't', 'c', 'f')
228 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
231 #define GASP_GRIDFIT 0x01
232 #define GASP_DOGRAY 0x02
234 #ifndef WINE_FONT_DIR
235 #define WINE_FONT_DIR "fonts"
238 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
245 FT_Short internal_leading
;
248 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
249 So to let this compile on older versions of FreeType we'll define the
250 new structure here. */
252 FT_Short height
, width
;
253 FT_Pos size
, x_ppem
, y_ppem
;
259 NEWTEXTMETRICEXW ntm
;
263 typedef struct tagFace
{
265 unsigned int refcount
;
272 DWORD font_data_size
;
276 FT_Fixed font_version
;
278 Bitmap_Size size
; /* set if face is a bitmap */
279 DWORD flags
; /* ADDFONT flags */
280 struct tagFamily
*family
;
281 /* Cached data for Enum */
282 struct enum_data
*cached_enum_data
;
285 #define ADDFONT_EXTERNAL_FONT 0x01
286 #define ADDFONT_ALLOW_BITMAP 0x02
287 #define ADDFONT_ADD_TO_CACHE 0x04
288 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
289 #define ADDFONT_VERTICAL_FONT 0x10
290 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
292 typedef struct tagFamily
{
294 unsigned int refcount
;
298 struct list
*replacement
;
303 ABC abc
; /* metrics of the unrotated char */
319 typedef struct tagGdiFont GdiFont
;
321 #define FIRST_FONT_HANDLE 1
322 #define MAX_FONT_HANDLES 256
324 struct font_handle_entry
327 WORD generation
; /* generation count for reusing handle values */
330 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
331 static struct font_handle_entry
*next_free
;
332 static struct font_handle_entry
*next_unused
= font_handles
;
334 static inline DWORD
entry_to_handle( struct font_handle_entry
*entry
)
336 unsigned int idx
= entry
- font_handles
+ FIRST_FONT_HANDLE
;
337 return idx
| (entry
->generation
<< 16);
340 static inline struct font_handle_entry
*handle_entry( DWORD handle
)
342 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
344 if (idx
< MAX_FONT_HANDLES
)
346 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
347 return &font_handles
[idx
];
349 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
353 static DWORD
alloc_font_handle( void *obj
)
355 struct font_handle_entry
*entry
;
359 next_free
= entry
->obj
;
360 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
361 entry
= next_unused
++;
364 ERR( "out of realized font handles\n" );
368 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
369 return entry_to_handle( entry
);
372 static void free_font_handle( DWORD handle
)
374 struct font_handle_entry
*entry
;
376 if ((entry
= handle_entry( handle
)))
378 entry
->obj
= next_free
;
389 struct font_fileinfo
{
397 struct list unused_entry
;
398 unsigned int refcount
;
401 OUTLINETEXTMETRICW
*potm
;
402 DWORD total_kern_pairs
;
403 KERNINGPAIR
*kern_pairs
;
404 struct list child_fonts
;
406 /* the following members can be accessed without locking, they are never modified after creation */
408 struct font_mapping
*mapping
;
424 UINT ntmCellHeight
, ntmAvgWidth
;
428 const VOID
*vert_feature
;
429 ULONG ttc_item_offset
; /* 0 if font is not a part of TrueType collection */
432 struct font_fileinfo
*fileinfo
;
437 const WCHAR
*font_name
;
442 struct enum_charset_element
{
445 WCHAR name
[LF_FACESIZE
];
448 struct enum_charset_list
{
450 struct enum_charset_element element
[32];
453 #define GM_BLOCK_SIZE 128
454 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
456 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
457 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
458 static unsigned int unused_font_count
;
459 #define UNUSED_CACHE_SIZE 10
460 static struct list system_links
= LIST_INIT(system_links
);
462 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
464 static struct list font_list
= LIST_INIT(font_list
);
466 struct freetype_physdev
468 struct gdi_physdev dev
;
472 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
474 return (struct freetype_physdev
*)dev
;
477 static const struct gdi_dc_funcs freetype_funcs
;
479 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
480 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
481 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
483 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
484 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
485 'W','i','n','d','o','w','s','\\',
486 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
487 'F','o','n','t','s','\0'};
489 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
490 'W','i','n','d','o','w','s',' ','N','T','\\',
491 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
492 'F','o','n','t','s','\0'};
494 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
495 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
496 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
497 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
499 static const WCHAR
* const SystemFontValues
[] = {
506 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
507 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
509 /* Interesting and well-known (frequently-assumed!) font names */
510 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
511 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 };
512 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
513 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
514 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
515 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
516 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
517 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
519 static const WCHAR arial
[] = {'A','r','i','a','l',0};
520 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
521 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};
522 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};
523 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
524 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
525 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
526 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
527 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
528 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
530 static const WCHAR
*default_serif_list
[] =
534 bitstream_vera_serif
,
538 static const WCHAR
*default_fixed_list
[] =
542 bitstream_vera_sans_mono
,
546 static const WCHAR
*default_sans_list
[] =
559 typedef struct tagFontSubst
{
565 /* Registry font cache key and value names */
566 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
567 'F','o','n','t','s',0};
568 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
569 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
570 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
571 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
572 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
573 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
574 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
575 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
576 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
577 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
578 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
579 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
580 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
581 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
582 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
595 static struct list mappings_list
= LIST_INIT( mappings_list
);
597 static UINT default_aa_flags
;
598 static HKEY hkey_font_cache
;
599 static BOOL antialias_fakes
= TRUE
;
601 static CRITICAL_SECTION freetype_cs
;
602 static CRITICAL_SECTION_DEBUG critsect_debug
=
605 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
606 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
608 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
610 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
612 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
613 static BOOL use_default_fallback
= FALSE
;
615 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
*vert
);
616 static BOOL
get_outline_text_metrics(GdiFont
*font
);
617 static BOOL
get_bitmap_text_metrics(GdiFont
*font
);
618 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
619 static void remove_face_from_cache( Face
*face
);
621 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
622 'W','i','n','d','o','w','s',' ','N','T','\\',
623 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
624 'S','y','s','t','e','m','L','i','n','k',0};
626 /****************************************
627 * Notes on .fon files
629 * The fonts System, FixedSys and Terminal are special. There are typically multiple
630 * versions installed for different resolutions and codepages. Windows stores which one to use
631 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
633 * FIXEDFON.FON FixedSys
635 * OEMFONT.FON Terminal
636 * LogPixels Current dpi set by the display control panel applet
637 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
638 * also has a LogPixels value that appears to mirror this)
640 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
641 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
642 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
643 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
644 * so that makes sense.
646 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
647 * to be mapped into the registry on Windows 2000 at least).
650 * ega80woa.fon=ega80850.fon
651 * ega40woa.fon=ega40850.fon
652 * cga80woa.fon=cga80850.fon
653 * cga40woa.fon=cga40850.fon
656 /* These are all structures needed for the GSUB table */
673 GSUB_ScriptRecord ScriptRecord
[1];
679 } GSUB_LangSysRecord
;
684 GSUB_LangSysRecord LangSysRecord
[1];
688 WORD LookupOrder
; /* Reserved */
689 WORD ReqFeatureIndex
;
691 WORD FeatureIndex
[1];
697 } GSUB_FeatureRecord
;
701 GSUB_FeatureRecord FeatureRecord
[1];
705 WORD FeatureParams
; /* Reserved */
707 WORD LookupListIndex
[1];
726 } GSUB_CoverageFormat1
;
731 WORD StartCoverageIndex
;
737 GSUB_RangeRecord RangeRecord
[1];
738 } GSUB_CoverageFormat2
;
741 WORD SubstFormat
; /* = 1 */
744 } GSUB_SingleSubstFormat1
;
747 WORD SubstFormat
; /* = 2 */
751 }GSUB_SingleSubstFormat2
;
753 #ifdef HAVE_CARBON_CARBON_H
754 static char *find_cache_dir(void)
758 static char cached_path
[MAX_PATH
];
759 static const char *wine
= "/Wine", *fonts
= "/Fonts";
761 if(*cached_path
) return cached_path
;
763 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
766 WARN("can't create cached data folder\n");
769 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
772 WARN("can't create cached data path\n");
776 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
778 ERR("Could not create full path\n");
782 strcat(cached_path
, wine
);
784 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
786 WARN("Couldn't mkdir %s\n", cached_path
);
790 strcat(cached_path
, fonts
);
791 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
793 WARN("Couldn't mkdir %s\n", cached_path
);
800 /******************************************************************
803 * Extracts individual TrueType font files from a Mac suitcase font
804 * and saves them into the user's caches directory (see
806 * Returns a NULL terminated array of filenames.
808 * We do this because they are apps that try to read ttf files
809 * themselves and they don't like Mac suitcase files.
811 static char **expand_mac_font(const char *path
)
818 const char *filename
;
822 unsigned int size
, max_size
;
825 TRACE("path %s\n", path
);
827 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
830 WARN("failed to get ref\n");
834 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
837 TRACE("no data fork, so trying resource fork\n");
838 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
841 TRACE("unable to open resource fork\n");
848 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
851 CloseResFile(res_ref
);
855 out_dir
= find_cache_dir();
857 filename
= strrchr(path
, '/');
858 if(!filename
) filename
= path
;
861 /* output filename has the form out_dir/filename_%04x.ttf */
862 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
869 unsigned short *num_faces_ptr
, num_faces
, face
;
872 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
874 fond
= Get1IndResource(fond_res
, idx
);
876 TRACE("got fond resource %d\n", idx
);
879 fam_rec
= *(FamRec
**)fond
;
880 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
881 num_faces
= GET_BE_WORD(*num_faces_ptr
);
883 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
884 TRACE("num faces %04x\n", num_faces
);
885 for(face
= 0; face
< num_faces
; face
++, assoc
++)
888 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
889 unsigned short size
, font_id
;
892 size
= GET_BE_WORD(assoc
->fontSize
);
893 font_id
= GET_BE_WORD(assoc
->fontID
);
896 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
900 TRACE("trying to load sfnt id %04x\n", font_id
);
901 sfnt
= GetResource(sfnt_res
, font_id
);
904 TRACE("can't get sfnt resource %04x\n", font_id
);
908 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
913 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
915 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
916 if(fd
!= -1 || errno
== EEXIST
)
920 unsigned char *sfnt_data
;
923 sfnt_data
= *(unsigned char**)sfnt
;
924 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
928 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
931 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
933 ret
.array
[ret
.size
++] = output
;
937 WARN("unable to create %s\n", output
);
938 HeapFree(GetProcessHeap(), 0, output
);
941 ReleaseResource(sfnt
);
944 ReleaseResource(fond
);
947 CloseResFile(res_ref
);
952 #endif /* HAVE_CARBON_CARBON_H */
954 static inline BOOL
is_win9x(void)
956 return GetVersion() & 0x80000000;
959 This function builds an FT_Fixed from a double. It fails if the absolute
960 value of the float number is greater than 32768.
962 static inline FT_Fixed
FT_FixedFromFloat(double f
)
968 This function builds an FT_Fixed from a FIXED. It simply put f.value
969 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
971 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
973 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
976 static BOOL
is_hinting_enabled(void)
978 static int enabled
= -1;
982 /* Use the >= 2.2.0 function if available */
983 if (pFT_Get_TrueType_Engine_Type
)
985 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
986 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
988 else enabled
= FALSE
;
989 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
994 static BOOL
is_subpixel_rendering_enabled( void )
996 #ifdef FT_LCD_FILTER_H
997 static int enabled
= -1;
1000 enabled
= (pFT_Library_SetLcdFilter
&&
1001 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
1002 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
1011 static const struct list
*get_face_list_from_family(const Family
*family
)
1013 if (!list_empty(&family
->faces
))
1014 return &family
->faces
;
1016 return family
->replacement
;
1019 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
1025 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
1027 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1029 const struct list
*face_list
;
1030 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
1032 face_list
= get_face_list_from_family(family
);
1033 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
1037 file
= strrchrW(face
->file
, '/');
1042 if(strcmpiW(file
, file_name
)) continue;
1050 static Family
*find_family_from_name(const WCHAR
*name
)
1054 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1056 if(!strcmpiW(family
->FamilyName
, name
))
1063 static Family
*find_family_from_any_name(const WCHAR
*name
)
1067 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1069 if(!strcmpiW(family
->FamilyName
, name
))
1071 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1078 static void DumpSubstList(void)
1082 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1084 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1085 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1086 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1088 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1089 debugstr_w(psub
->to
.name
));
1093 static LPWSTR
strdupW(LPCWSTR p
)
1096 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1097 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1098 memcpy(ret
, p
, len
);
1102 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1107 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1109 if(!strcmpiW(element
->from
.name
, from_name
) &&
1110 (element
->from
.charset
== from_charset
||
1111 element
->from
.charset
== -1))
1118 #define ADD_FONT_SUBST_FORCE 1
1120 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1122 FontSubst
*from_exist
, *to_exist
;
1124 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1126 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1128 list_remove(&from_exist
->entry
);
1129 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1130 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1131 HeapFree(GetProcessHeap(), 0, from_exist
);
1137 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1141 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1142 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1145 list_add_tail(subst_list
, &subst
->entry
);
1150 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1151 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1152 HeapFree(GetProcessHeap(), 0, subst
);
1156 static WCHAR
*towstr(UINT cp
, const char *str
)
1161 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1162 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1163 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1167 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1169 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1170 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1171 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1175 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1177 CHAR
*p
= strrchr(str
, ',');
1181 nc
->charset
= strtol(p
+1, NULL
, 10);
1184 nc
->name
= towstr(CP_ACP
, str
);
1187 static void LoadSubstList(void)
1191 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1195 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1196 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1197 &hkey
) == ERROR_SUCCESS
) {
1199 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1200 &valuelen
, &datalen
, NULL
, NULL
);
1202 valuelen
++; /* returned value doesn't include room for '\0' */
1203 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1204 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1208 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1209 &dlen
) == ERROR_SUCCESS
) {
1210 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1212 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1213 split_subst_info(&psub
->from
, value
);
1214 split_subst_info(&psub
->to
, data
);
1216 /* Win 2000 doesn't allow mapping between different charsets
1217 or mapping of DEFAULT_CHARSET */
1218 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1219 psub
->to
.charset
== DEFAULT_CHARSET
) {
1220 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1221 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1222 HeapFree(GetProcessHeap(), 0, psub
);
1224 add_font_subst(&font_subst_list
, psub
, 0);
1226 /* reset dlen and vlen */
1230 HeapFree(GetProcessHeap(), 0, data
);
1231 HeapFree(GetProcessHeap(), 0, value
);
1237 static const LANGID mac_langid_table
[] =
1239 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
1240 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
1241 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
1242 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
1243 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
1244 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
1245 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
1246 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
1247 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
1248 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
1249 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
1250 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
1251 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
1252 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
1253 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
1254 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
1255 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
1256 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
1257 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
1258 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1259 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
1260 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
1261 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
1262 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
1263 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
1264 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
1265 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
1266 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
1267 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
1268 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
1269 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
1270 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
1271 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
1272 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1273 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
1274 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
1275 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
1276 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
1277 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
1278 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
1279 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
1280 0, /* TT_MAC_LANGID_YIDDISH */
1281 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
1282 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
1283 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
1284 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
1285 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
1286 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
1287 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
1288 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
1289 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1290 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
1291 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
1292 0, /* TT_MAC_LANGID_MOLDAVIAN */
1293 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
1294 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
1295 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
1296 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
1297 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1298 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
1299 0, /* TT_MAC_LANGID_KURDISH */
1300 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
1301 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
1302 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
1303 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
1304 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
1305 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
1306 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
1307 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
1308 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
1309 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
1310 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
1311 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
1312 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
1313 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
1314 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
1315 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
1316 0, /* TT_MAC_LANGID_BURMESE */
1317 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
1318 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
1319 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
1320 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
1321 0, /* TT_MAC_LANGID_TAGALOG */
1322 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1323 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1324 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
1325 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
1326 0, /* TT_MAC_LANGID_GALLA */
1327 0, /* TT_MAC_LANGID_SOMALI */
1328 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
1329 0, /* TT_MAC_LANGID_RUANDA */
1330 0, /* TT_MAC_LANGID_RUNDI */
1331 0, /* TT_MAC_LANGID_CHEWA */
1332 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
1333 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
1334 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1336 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
1337 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
1338 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
1339 0, /* TT_MAC_LANGID_LATIN */
1340 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
1341 0, /* TT_MAC_LANGID_GUARANI */
1342 0, /* TT_MAC_LANGID_AYMARA */
1343 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
1344 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
1345 0, /* TT_MAC_LANGID_DZONGKHA */
1346 0, /* TT_MAC_LANGID_JAVANESE */
1347 0, /* TT_MAC_LANGID_SUNDANESE */
1348 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
1349 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
1350 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
1351 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
1352 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1353 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
1354 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
1355 0, /* TT_MAC_LANGID_TONGAN */
1356 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1357 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
1358 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1361 static inline WORD
get_mac_code_page( const FT_SfntName
*name
)
1363 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
1364 return 10000 + name
->encoding_id
;
1367 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
1372 switch (name
->platform_id
)
1374 case TT_PLATFORM_MICROSOFT
:
1375 res
+= 5; /* prefer the Microsoft name */
1376 switch (name
->encoding_id
)
1378 case TT_MS_ID_UNICODE_CS
:
1379 case TT_MS_ID_SYMBOL_CS
:
1380 name_lang
= name
->language_id
;
1386 case TT_PLATFORM_MACINTOSH
:
1387 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
1388 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1389 name_lang
= mac_langid_table
[name
->language_id
];
1391 case TT_PLATFORM_APPLE_UNICODE
:
1392 res
+= 2; /* prefer Unicode encodings */
1393 switch (name
->encoding_id
)
1395 case TT_APPLE_ID_DEFAULT
:
1396 case TT_APPLE_ID_ISO_10646
:
1397 case TT_APPLE_ID_UNICODE_2_0
:
1398 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1399 name_lang
= mac_langid_table
[name
->language_id
];
1408 if (name_lang
== lang
) res
+= 30;
1409 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
1410 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
1414 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
1420 switch (name
->platform_id
)
1422 case TT_PLATFORM_APPLE_UNICODE
:
1423 case TT_PLATFORM_MICROSOFT
:
1424 ret
= HeapAlloc( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
1425 for (i
= 0; i
< name
->string_len
/ 2; i
++)
1426 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
1429 case TT_PLATFORM_MACINTOSH
:
1430 codepage
= get_mac_code_page( name
);
1431 i
= MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, NULL
, 0 );
1432 ret
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(WCHAR
) );
1433 MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, ret
, i
);
1440 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
1443 FT_UInt num_names
, name_index
;
1444 int res
, best_lang
= 0, best_index
= -1;
1446 if (!FT_IS_SFNT(ft_face
)) return NULL
;
1448 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
1450 for (name_index
= 0; name_index
< num_names
; name_index
++)
1452 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
1453 if (name
.name_id
!= name_id
) continue;
1454 res
= match_name_table_language( &name
, language_id
);
1455 if (res
> best_lang
)
1458 best_index
= name_index
;
1462 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
1464 WCHAR
*ret
= copy_name_table_string( &name
);
1465 TRACE( "name %u found platform %u lang %04x %s\n",
1466 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
1472 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1474 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1475 if (f1
->scalable
) return TRUE
;
1476 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1477 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1480 static void release_family( Family
*family
)
1482 if (--family
->refcount
) return;
1483 assert( list_empty( &family
->faces
));
1484 list_remove( &family
->entry
);
1485 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1486 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1487 HeapFree( GetProcessHeap(), 0, family
);
1490 static void release_face( Face
*face
)
1492 if (--face
->refcount
) return;
1495 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1496 list_remove( &face
->entry
);
1497 release_family( face
->family
);
1499 HeapFree( GetProcessHeap(), 0, face
->file
);
1500 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1501 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1502 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1503 HeapFree( GetProcessHeap(), 0, face
);
1506 static inline int style_order(const Face
*face
)
1508 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1516 case NTM_BOLD
| NTM_ITALIC
:
1519 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1520 debugstr_w(face
->family
->FamilyName
),
1521 debugstr_w(face
->StyleName
),
1527 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1531 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1533 if (faces_equal( face
, cursor
))
1535 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1536 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1537 cursor
->font_version
, face
->font_version
);
1539 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1542 TRACE("Font %s already in list, refcount now %d\n",
1543 debugstr_w(face
->file
), cursor
->refcount
);
1546 if (face
->font_version
<= cursor
->font_version
)
1548 TRACE("Original font %s is newer so skipping %s\n",
1549 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1554 TRACE("Replacing original %s with %s\n",
1555 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1556 list_add_before( &cursor
->entry
, &face
->entry
);
1557 face
->family
= family
;
1560 release_face( cursor
);
1565 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1567 if (style_order( face
) < style_order( cursor
)) break;
1570 list_add_before( &cursor
->entry
, &face
->entry
);
1571 face
->family
= family
;
1577 /****************************************************************
1578 * NB This function stores the ptrs to the strings to save copying.
1579 * Don't free them after calling.
1581 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1583 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1584 family
->refcount
= 1;
1585 family
->FamilyName
= name
;
1586 family
->EnglishName
= english_name
;
1587 list_init( &family
->faces
);
1588 family
->replacement
= &family
->faces
;
1589 list_add_tail( &font_list
, &family
->entry
);
1594 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1596 DWORD type
, size
= sizeof(DWORD
);
1598 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1599 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1602 return ERROR_BAD_CONFIGURATION
;
1604 return ERROR_SUCCESS
;
1607 static inline LONG
reg_load_ftlong(HKEY hkey
, const WCHAR
*value
, FT_Long
*data
)
1610 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1615 static inline LONG
reg_load_ftshort(HKEY hkey
, const WCHAR
*value
, FT_Short
*data
)
1618 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1623 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1625 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1628 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1630 DWORD needed
, strike_index
= 0;
1633 /* If we have a File Name key then this is a real font, not just the parent
1634 key of a bunch of non-scalable strikes */
1635 needed
= buffer_size
;
1636 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1639 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1640 face
->cached_enum_data
= NULL
;
1641 face
->family
= NULL
;
1644 face
->file
= strdupW( buffer
);
1645 face
->StyleName
= strdupW(face_name
);
1647 needed
= buffer_size
;
1648 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1649 face
->FullName
= strdupW( buffer
);
1651 face
->FullName
= NULL
;
1653 reg_load_ftlong(hkey_face
, face_index_value
, &face
->face_index
);
1654 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1655 reg_load_ftlong(hkey_face
, face_version_value
, &face
->font_version
);
1656 reg_load_dword(hkey_face
, face_flags_value
, &face
->flags
);
1658 needed
= sizeof(face
->fs
);
1659 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1661 if(reg_load_ftshort(hkey_face
, face_height_value
, &face
->size
.height
) != ERROR_SUCCESS
)
1663 face
->scalable
= TRUE
;
1664 memset(&face
->size
, 0, sizeof(face
->size
));
1668 face
->scalable
= FALSE
;
1669 reg_load_ftshort(hkey_face
, face_width_value
, &face
->size
.width
);
1670 reg_load_ftlong(hkey_face
, face_size_value
, &face
->size
.size
);
1671 reg_load_ftlong(hkey_face
, face_x_ppem_value
, &face
->size
.x_ppem
);
1672 reg_load_ftlong(hkey_face
, face_y_ppem_value
, &face
->size
.y_ppem
);
1673 reg_load_ftshort(hkey_face
, face_internal_leading_value
, &face
->size
.internal_leading
);
1675 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1676 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1677 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1680 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1681 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1682 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1683 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1685 if (insert_face_in_family_list(face
, family
))
1686 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1688 release_face( face
);
1691 /* load bitmap strikes */
1693 needed
= buffer_size
;
1694 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1696 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1698 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1699 RegCloseKey(hkey_strike
);
1701 needed
= buffer_size
;
1705 /* move vertical fonts after their horizontal counterpart */
1706 /* assumes that font_list is already sorted by family name */
1707 static void reorder_vertical_fonts(void)
1709 Family
*family
, *next
, *vert_family
;
1710 struct list
*ptr
, *vptr
;
1711 struct list vertical_families
= LIST_INIT( vertical_families
);
1713 LIST_FOR_EACH_ENTRY_SAFE( family
, next
, &font_list
, Family
, entry
)
1715 if (family
->FamilyName
[0] != '@') continue;
1716 list_remove( &family
->entry
);
1717 list_add_tail( &vertical_families
, &family
->entry
);
1720 ptr
= list_head( &font_list
);
1721 vptr
= list_head( &vertical_families
);
1724 family
= LIST_ENTRY( ptr
, Family
, entry
);
1725 vert_family
= LIST_ENTRY( vptr
, Family
, entry
);
1726 if (strcmpiW( family
->FamilyName
, vert_family
->FamilyName
+ 1 ) > 0)
1728 list_remove( vptr
);
1729 list_add_before( ptr
, vptr
);
1730 vptr
= list_head( &vertical_families
);
1732 else ptr
= list_next( &font_list
, ptr
);
1734 list_move_tail( &font_list
, &vertical_families
);
1737 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1739 DWORD size
, family_index
= 0;
1744 size
= sizeof(buffer
);
1745 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1747 WCHAR
*english_family
= NULL
;
1748 WCHAR
*family_name
= strdupW( buffer
);
1749 DWORD face_index
= 0;
1751 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1752 TRACE("opened family key %s\n", debugstr_w(family_name
));
1753 size
= sizeof(buffer
);
1754 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1755 english_family
= strdupW( buffer
);
1757 family
= create_family(family_name
, english_family
);
1761 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1762 subst
->from
.name
= strdupW(english_family
);
1763 subst
->from
.charset
= -1;
1764 subst
->to
.name
= strdupW(family_name
);
1765 subst
->to
.charset
= -1;
1766 add_font_subst(&font_subst_list
, subst
, 0);
1769 size
= sizeof(buffer
);
1770 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1772 WCHAR
*face_name
= strdupW( buffer
);
1775 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1777 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1778 RegCloseKey(hkey_face
);
1780 HeapFree( GetProcessHeap(), 0, face_name
);
1781 size
= sizeof(buffer
);
1783 RegCloseKey(hkey_family
);
1784 release_family( family
);
1785 size
= sizeof(buffer
);
1788 reorder_vertical_fonts();
1791 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1794 HKEY hkey_wine_fonts
;
1796 /* We don't want to create the fonts key as volatile, so open this first */
1797 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1798 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1799 if(ret
!= ERROR_SUCCESS
)
1801 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1805 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1806 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1807 RegCloseKey(hkey_wine_fonts
);
1811 static void add_face_to_cache(Face
*face
)
1813 HKEY hkey_family
, hkey_face
;
1814 WCHAR
*face_key_name
;
1816 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1817 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1818 if(face
->family
->EnglishName
)
1819 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1820 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1823 face_key_name
= face
->StyleName
;
1826 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1827 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1828 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1830 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1833 HeapFree(GetProcessHeap(), 0, face_key_name
);
1835 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1836 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1838 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1839 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1841 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1842 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1843 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1844 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1846 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1850 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1851 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1852 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1853 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1854 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1855 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1857 RegCloseKey(hkey_face
);
1858 RegCloseKey(hkey_family
);
1861 static void remove_face_from_cache( Face
*face
)
1865 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1869 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1873 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1874 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1875 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1876 RegDeleteKeyW( hkey_family
, face_key_name
);
1877 HeapFree(GetProcessHeap(), 0, face_key_name
);
1879 RegCloseKey(hkey_family
);
1882 static WCHAR
*prepend_at(WCHAR
*family
)
1889 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1891 strcpyW(str
+ 1, family
);
1892 HeapFree(GetProcessHeap(), 0, family
);
1896 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1898 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
) );
1899 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1901 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1907 else if (!strcmpiW( *name
, *english
))
1909 HeapFree( GetProcessHeap(), 0, *english
);
1915 *name
= prepend_at( *name
);
1916 *english
= prepend_at( *english
);
1920 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1923 WCHAR
*name
, *english_name
;
1925 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1927 family
= find_family_from_name( name
);
1931 family
= create_family( name
, english_name
);
1934 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1935 subst
->from
.name
= strdupW( english_name
);
1936 subst
->from
.charset
= -1;
1937 subst
->to
.name
= strdupW( name
);
1938 subst
->to
.charset
= -1;
1939 add_font_subst( &font_subst_list
, subst
, 0 );
1944 HeapFree( GetProcessHeap(), 0, name
);
1945 HeapFree( GetProcessHeap(), 0, english_name
);
1952 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1954 FT_Fixed version
= 0;
1957 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1958 if (header
) version
= header
->Font_Revision
;
1963 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1966 FT_ULong table_size
= 0;
1967 FT_WinFNT_HeaderRec winfnt_header
;
1969 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1970 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1972 /* fixup the flag for our fake-bold implementation. */
1973 if (!FT_IS_SCALABLE( ft_face
) &&
1974 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
1975 winfnt_header
.weight
> FW_NORMAL
)
1978 if (flags
== 0) flags
= NTM_REGULAR
;
1980 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1981 flags
|= NTM_PS_OPENTYPE
;
1986 static inline void get_bitmap_size( FT_Face ft_face
, Bitmap_Size
*face_size
)
1988 My_FT_Bitmap_Size
*size
;
1989 FT_WinFNT_HeaderRec winfnt_header
;
1991 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1992 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1993 size
->height
, size
->width
, size
->size
>> 6,
1994 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1995 face_size
->height
= size
->height
;
1996 face_size
->width
= size
->width
;
1997 face_size
->size
= size
->size
;
1998 face_size
->x_ppem
= size
->x_ppem
;
1999 face_size
->y_ppem
= size
->y_ppem
;
2001 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
2002 face_size
->internal_leading
= winfnt_header
.internal_leading
;
2003 if (winfnt_header
.external_leading
> 0 &&
2004 (face_size
->height
==
2005 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
2006 face_size
->height
= winfnt_header
.pixel_height
;
2010 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
2015 FT_WinFNT_HeaderRec winfnt_header
;
2018 memset( fs
, 0, sizeof(*fs
) );
2020 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
2023 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
2024 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
2025 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
2026 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
2028 if (os2
->version
== 0)
2030 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
2031 fs
->fsCsb
[0] = FS_LATIN1
;
2033 fs
->fsCsb
[0] = FS_SYMBOL
;
2037 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
2038 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
2043 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
2045 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
2046 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
2047 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
2052 if (fs
->fsCsb
[0] == 0)
2054 /* let's see if we can find any interesting cmaps */
2055 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2057 switch (ft_face
->charmaps
[i
]->encoding
)
2059 case FT_ENCODING_UNICODE
:
2060 case FT_ENCODING_APPLE_ROMAN
:
2061 fs
->fsCsb
[0] |= FS_LATIN1
;
2063 case FT_ENCODING_MS_SYMBOL
:
2064 fs
->fsCsb
[0] |= FS_SYMBOL
;
2073 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2077 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
2080 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
2081 if (!face
->StyleName
) face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
2083 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
2084 if (flags
& ADDFONT_VERTICAL_FONT
)
2085 face
->FullName
= prepend_at( face
->FullName
);
2091 face
->file
= towstr( CP_UNIXCP
, file
);
2092 face
->font_data_ptr
= NULL
;
2093 face
->font_data_size
= 0;
2094 if (!stat( file
, &st
))
2096 face
->dev
= st
.st_dev
;
2097 face
->ino
= st
.st_ino
;
2103 face
->font_data_ptr
= font_data_ptr
;
2104 face
->font_data_size
= font_data_size
;
2107 face
->face_index
= face_index
;
2108 get_fontsig( ft_face
, &face
->fs
);
2109 face
->ntmFlags
= get_ntm_flags( ft_face
);
2110 face
->font_version
= get_font_version( ft_face
);
2112 if (FT_IS_SCALABLE( ft_face
))
2114 memset( &face
->size
, 0, sizeof(face
->size
) );
2115 face
->scalable
= TRUE
;
2119 get_bitmap_size( ft_face
, &face
->size
);
2120 face
->scalable
= FALSE
;
2123 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
2124 face
->flags
= flags
;
2125 face
->family
= NULL
;
2126 face
->cached_enum_data
= NULL
;
2128 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2129 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
2130 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
2131 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
2136 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2137 FT_Long face_index
, DWORD flags
)
2142 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
2143 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
2144 if (strlenW(family
->FamilyName
) >= LF_FACESIZE
)
2146 WARN("Ignoring %s because name is too long\n", debugstr_w(family
->FamilyName
));
2147 release_face( face
);
2148 release_family( family
);
2152 if (insert_face_in_family_list( face
, family
))
2154 if (flags
& ADDFONT_ADD_TO_CACHE
)
2155 add_face_to_cache( face
);
2157 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
2158 debugstr_w(face
->StyleName
));
2160 release_face( face
);
2161 release_family( family
);
2164 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2165 FT_Long face_index
, BOOL allow_bitmap
)
2173 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
2174 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
2178 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
2179 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
2184 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
2188 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2189 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
2191 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2195 if (!FT_IS_SFNT( ft_face
))
2197 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
2199 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2205 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
2206 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
2207 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
2209 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2210 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
2214 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2215 we don't want to load these. */
2216 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
2220 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
2222 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
2228 if (!ft_face
->family_name
|| !ft_face
->style_name
)
2230 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
2236 pFT_Done_Face( ft_face
);
2240 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
2243 FT_Long face_index
= 0, num_faces
;
2246 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2247 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
2249 #ifdef HAVE_CARBON_CARBON_H
2252 char **mac_list
= expand_mac_font(file
);
2255 BOOL had_one
= FALSE
;
2257 for(cursor
= mac_list
; *cursor
; cursor
++)
2260 AddFontToList(*cursor
, NULL
, 0, flags
);
2261 HeapFree(GetProcessHeap(), 0, *cursor
);
2263 HeapFree(GetProcessHeap(), 0, mac_list
);
2268 #endif /* HAVE_CARBON_CARBON_H */
2271 const DWORD FS_DBCS_MASK
= FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
;
2274 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
2275 if (!ft_face
) return 0;
2277 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
2279 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
2280 pFT_Done_Face(ft_face
);
2284 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
2287 get_fontsig(ft_face
, &fs
);
2288 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
2290 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
2291 flags
| ADDFONT_VERTICAL_FONT
);
2295 num_faces
= ft_face
->num_faces
;
2296 pFT_Done_Face(ft_face
);
2297 } while(num_faces
> ++face_index
);
2301 static int remove_font_resource( const char *file
, DWORD flags
)
2303 Family
*family
, *family_next
;
2304 Face
*face
, *face_next
;
2308 if (stat( file
, &st
) == -1) return 0;
2309 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2312 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2314 if (!face
->file
) continue;
2315 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2316 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2318 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2319 release_face( face
);
2323 release_family( family
);
2328 static void DumpFontList(void)
2333 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2334 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2335 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2336 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2338 TRACE(" %d", face
->size
.height
);
2344 static BOOL
map_font_family(const WCHAR
*orig
, const WCHAR
*repl
)
2346 Family
*family
= find_family_from_any_name(repl
);
2349 Family
*new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2350 if (new_family
!= NULL
)
2352 TRACE("mapping %s to %s\n", debugstr_w(repl
), debugstr_w(orig
));
2353 new_family
->FamilyName
= strdupW(orig
);
2354 new_family
->EnglishName
= NULL
;
2355 list_init(&new_family
->faces
);
2356 new_family
->replacement
= &family
->faces
;
2357 list_add_tail(&font_list
, &new_family
->entry
);
2361 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl
));
2365 /***********************************************************
2366 * The replacement list is a way to map an entire font
2367 * family onto another family. For example adding
2369 * [HKCU\Software\Wine\Fonts\Replacements]
2370 * "Wingdings"="Winedings"
2372 * would enumerate the Winedings font both as Winedings and
2373 * Wingdings. However if a real Wingdings font is present the
2374 * replacement does not take place.
2377 static void LoadReplaceList(void)
2380 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2384 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2385 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2387 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2388 &valuelen
, &datalen
, NULL
, NULL
);
2390 valuelen
++; /* returned value doesn't include room for '\0' */
2391 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2392 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2396 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
, &dlen
) == ERROR_SUCCESS
)
2398 /* "NewName"="Oldname" */
2399 if(!find_family_from_any_name(value
))
2401 if (type
== REG_MULTI_SZ
)
2403 WCHAR
*replace
= data
;
2406 if (map_font_family(value
, replace
))
2408 replace
+= strlenW(replace
) + 1;
2411 else if (type
== REG_SZ
)
2412 map_font_family(value
, data
);
2415 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2417 /* reset dlen and vlen */
2421 HeapFree(GetProcessHeap(), 0, data
);
2422 HeapFree(GetProcessHeap(), 0, value
);
2427 static const WCHAR
*font_links_list
[] =
2429 Lucida_Sans_Unicode
,
2430 Microsoft_Sans_Serif
,
2434 static const struct font_links_defaults_list
2436 /* Keyed off substitution for "MS Shell Dlg" */
2437 const WCHAR
*shelldlg
;
2438 /* Maximum of four substitutes, plus terminating NULL pointer */
2439 const WCHAR
*substitutes
[5];
2440 } font_links_defaults_list
[] =
2442 /* Non East-Asian */
2443 { Tahoma
, /* FIXME unverified ordering */
2444 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2446 /* Below lists are courtesy of
2447 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2451 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2453 /* Chinese Simplified */
2455 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2459 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2461 /* Chinese Traditional */
2463 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2468 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2470 SYSTEM_LINKS
*font_link
;
2472 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2474 if(!strcmpiW(font_link
->font_name
, name
))
2481 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2492 SYSTEM_LINKS
*font_link
;
2494 psub
= get_font_subst(&font_subst_list
, name
, -1);
2495 /* Don't store fonts that are only substitutes for other fonts */
2498 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2502 font_link
= find_font_link(name
);
2503 if (font_link
== NULL
)
2505 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2506 font_link
->font_name
= strdupW(name
);
2507 list_init(&font_link
->links
);
2508 list_add_tail(&system_links
, &font_link
->entry
);
2511 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2512 for (i
= 0; values
[i
] != NULL
; i
++)
2514 const struct list
*face_list
;
2515 CHILD_FONT
*child_font
;
2518 if (!strcmpiW(name
,value
))
2520 psub
= get_font_subst(&font_subst_list
, value
, -1);
2522 value
= psub
->to
.name
;
2523 family
= find_family_from_name(value
);
2527 /* Use first extant filename for this Family */
2528 face_list
= get_face_list_from_family(family
);
2529 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2533 file
= strrchrW(face
->file
, '/');
2542 face
= find_face_from_filename(file
, value
);
2545 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2549 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2550 child_font
->face
= face
;
2551 child_font
->font
= NULL
;
2552 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2553 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2554 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2555 child_font
->face
->face_index
);
2556 list_add_tail(&font_link
->links
, &child_font
->entry
);
2558 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2564 /*************************************************************
2567 static BOOL
init_system_links(void)
2571 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2572 WCHAR
*value
, *data
;
2573 WCHAR
*entry
, *next
;
2574 SYSTEM_LINKS
*font_link
, *system_font_link
;
2575 CHILD_FONT
*child_font
;
2576 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2577 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2578 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2583 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2585 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2586 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2587 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2588 val_len
= max_val
+ 1;
2589 data_len
= max_data
;
2591 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2593 psub
= get_font_subst(&font_subst_list
, value
, -1);
2594 /* Don't store fonts that are only substitutes for other fonts */
2597 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2600 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2601 font_link
->font_name
= strdupW(value
);
2602 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2603 list_init(&font_link
->links
);
2604 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2607 CHILD_FONT
*child_font
;
2609 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2611 next
= entry
+ strlenW(entry
) + 1;
2613 face_name
= strchrW(entry
, ',');
2617 while(isspaceW(*face_name
))
2620 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2622 face_name
= psub
->to
.name
;
2624 face
= find_face_from_filename(entry
, face_name
);
2627 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2631 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2632 child_font
->face
= face
;
2633 child_font
->font
= NULL
;
2634 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2635 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2636 TRACE("Adding file %s index %ld\n",
2637 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2638 list_add_tail(&font_link
->links
, &child_font
->entry
);
2640 list_add_tail(&system_links
, &font_link
->entry
);
2642 val_len
= max_val
+ 1;
2643 data_len
= max_data
;
2646 HeapFree(GetProcessHeap(), 0, value
);
2647 HeapFree(GetProcessHeap(), 0, data
);
2652 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2654 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2658 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2660 const FontSubst
*psub2
;
2661 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2663 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2665 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2666 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2668 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2669 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2671 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2673 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2679 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2682 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2683 system_font_link
->font_name
= strdupW(System
);
2684 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2685 list_init(&system_font_link
->links
);
2687 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2690 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2691 child_font
->face
= face
;
2692 child_font
->font
= NULL
;
2693 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2694 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2695 TRACE("Found Tahoma in %s index %ld\n",
2696 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2697 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2699 font_link
= find_font_link(Tahoma
);
2700 if (font_link
!= NULL
)
2702 CHILD_FONT
*font_link_entry
;
2703 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2705 CHILD_FONT
*new_child
;
2706 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2707 new_child
->face
= font_link_entry
->face
;
2708 new_child
->font
= NULL
;
2709 new_child
->face
->refcount
++;
2710 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2711 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2712 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2715 list_add_tail(&system_links
, &system_font_link
->entry
);
2719 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2722 struct dirent
*dent
;
2723 char path
[MAX_PATH
];
2725 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2727 dir
= opendir(dirname
);
2729 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2732 while((dent
= readdir(dir
)) != NULL
) {
2733 struct stat statbuf
;
2735 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2738 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2740 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2742 if(stat(path
, &statbuf
) == -1)
2744 WARN("Can't stat %s\n", debugstr_a(path
));
2747 if(S_ISDIR(statbuf
.st_mode
))
2748 ReadFontDir(path
, external_fonts
);
2751 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2752 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2753 AddFontToList(path
, NULL
, 0, addfont_flags
);
2760 #ifdef SONAME_LIBFONTCONFIG
2762 static BOOL fontconfig_enabled
;
2764 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2770 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2771 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2773 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2777 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2778 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2779 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2780 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2781 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2787 static void init_fontconfig(void)
2789 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2793 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2797 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2798 LOAD_FUNCPTR(FcConfigSubstitute
);
2799 LOAD_FUNCPTR(FcFontList
);
2800 LOAD_FUNCPTR(FcFontSetDestroy
);
2801 LOAD_FUNCPTR(FcInit
);
2802 LOAD_FUNCPTR(FcObjectSetAdd
);
2803 LOAD_FUNCPTR(FcObjectSetCreate
);
2804 LOAD_FUNCPTR(FcObjectSetDestroy
);
2805 LOAD_FUNCPTR(FcPatternCreate
);
2806 LOAD_FUNCPTR(FcPatternDestroy
);
2807 LOAD_FUNCPTR(FcPatternGetBool
);
2808 LOAD_FUNCPTR(FcPatternGetInteger
);
2809 LOAD_FUNCPTR(FcPatternGetString
);
2814 FcPattern
*pattern
= pFcPatternCreate();
2815 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2816 default_aa_flags
= parse_aa_pattern( pattern
);
2817 pFcPatternDestroy( pattern
);
2818 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2819 fontconfig_enabled
= TRUE
;
2823 static void load_fontconfig_fonts(void)
2832 if (!fontconfig_enabled
) return;
2834 pat
= pFcPatternCreate();
2835 os
= pFcObjectSetCreate();
2836 pFcObjectSetAdd(os
, FC_FILE
);
2837 pFcObjectSetAdd(os
, FC_SCALABLE
);
2838 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2839 pFcObjectSetAdd(os
, FC_RGBA
);
2840 fontset
= pFcFontList(NULL
, pat
, os
);
2841 if(!fontset
) return;
2842 for(i
= 0; i
< fontset
->nfont
; i
++) {
2846 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2849 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2851 /* We're just interested in OT/TT fonts for now, so this hack just
2852 picks up the scalable fonts without extensions .pf[ab] to save time
2853 loading every other font */
2855 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2857 TRACE("not scalable\n");
2861 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2862 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2864 len
= strlen( file
);
2865 if(len
< 4) continue;
2866 ext
= &file
[ len
- 3 ];
2867 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2868 AddFontToList(file
, NULL
, 0,
2869 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2871 pFcFontSetDestroy(fontset
);
2872 pFcObjectSetDestroy(os
);
2873 pFcPatternDestroy(pat
);
2876 #elif defined(HAVE_CARBON_CARBON_H)
2878 static void load_mac_font_callback(const void *value
, void *context
)
2880 CFStringRef pathStr
= value
;
2884 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2885 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2886 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2888 TRACE("font file %s\n", path
);
2889 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2891 HeapFree(GetProcessHeap(), 0, path
);
2894 static void load_mac_fonts(void)
2896 CFStringRef removeDupesKey
;
2897 CFBooleanRef removeDupesValue
;
2898 CFDictionaryRef options
;
2899 CTFontCollectionRef col
;
2901 CFMutableSetRef paths
;
2904 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2905 removeDupesValue
= kCFBooleanTrue
;
2906 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2907 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2908 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2909 if (options
) CFRelease(options
);
2912 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2916 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2920 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2924 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2927 WARN("CFSetCreateMutable failed\n");
2932 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2934 CTFontDescriptorRef desc
;
2939 desc
= CFArrayGetValueAtIndex(descs
, i
);
2941 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2942 url
= CTFontDescriptorCopyAttribute(desc
, kCTFontURLAttribute
);
2944 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
2945 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2952 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2953 if (!font
) continue;
2955 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2962 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2964 if (status
!= noErr
) continue;
2966 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2971 ext
= CFURLCopyPathExtension(url
);
2974 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2975 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2984 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2986 if (!path
) continue;
2988 CFSetAddValue(paths
, path
);
2994 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
3000 static char *get_font_dir(void)
3002 const char *build_dir
, *data_dir
;
3005 if ((data_dir
= wine_get_data_dir()))
3007 if (!(name
= HeapAlloc( GetProcessHeap(), 0, strlen(data_dir
) + 1 + sizeof(WINE_FONT_DIR
) )))
3009 strcpy( name
, data_dir
);
3010 strcat( name
, "/" );
3011 strcat( name
, WINE_FONT_DIR
);
3013 else if ((build_dir
= wine_get_build_dir()))
3015 if (!(name
= HeapAlloc( GetProcessHeap(), 0, strlen(build_dir
) + sizeof("/fonts") )))
3017 strcpy( name
, build_dir
);
3018 strcat( name
, "/fonts" );
3023 static char *get_data_dir_path( LPCWSTR file
)
3025 char *unix_name
= NULL
;
3026 char *font_dir
= get_font_dir();
3030 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
3032 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(font_dir
) + len
+ 1 );
3033 strcpy(unix_name
, font_dir
);
3034 strcat(unix_name
, "/");
3036 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
3037 HeapFree( GetProcessHeap(), 0, font_dir
);
3042 static BOOL
load_font_from_data_dir(LPCWSTR file
)
3045 char *unix_name
= get_data_dir_path( file
);
3049 EnterCriticalSection( &freetype_cs
);
3050 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3051 LeaveCriticalSection( &freetype_cs
);
3052 HeapFree(GetProcessHeap(), 0, unix_name
);
3057 static char *get_winfonts_dir_path(LPCWSTR file
)
3059 static const WCHAR slashW
[] = {'\\','\0'};
3060 WCHAR windowsdir
[MAX_PATH
];
3062 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3063 strcatW(windowsdir
, fontsW
);
3064 strcatW(windowsdir
, slashW
);
3065 strcatW(windowsdir
, file
);
3066 return wine_get_unix_file_name( windowsdir
);
3069 static void load_system_fonts(void)
3072 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
3073 const WCHAR
* const *value
;
3075 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3078 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3079 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3080 strcatW(windowsdir
, fontsW
);
3081 for(value
= SystemFontValues
; *value
; value
++) {
3082 dlen
= sizeof(data
);
3083 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
3087 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3088 if((unixname
= wine_get_unix_file_name(pathW
))) {
3089 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3090 HeapFree(GetProcessHeap(), 0, unixname
);
3093 load_font_from_data_dir(data
);
3100 /*************************************************************
3102 * This adds registry entries for any externally loaded fonts
3103 * (fonts from fontconfig or FontDirs). It also deletes entries
3104 * of no longer existing fonts.
3107 static void update_reg_entries(void)
3109 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3115 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
3117 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3118 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3119 ERR("Can't create Windows font reg key\n");
3123 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3124 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3125 ERR("Can't create Windows font reg key\n");
3129 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
3130 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
3131 ERR("Can't create external font reg key\n");
3135 /* enumerate the fonts and add external ones to the two keys */
3137 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
3138 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
3142 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
3144 name
= face
->FullName
? face
->FullName
: family
->FamilyName
;
3146 len
= strlenW(name
) + 1;
3148 len
+= sizeof(TrueType
) / sizeof(WCHAR
);
3150 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3151 strcpyW(valueW
, name
);
3154 strcatW(valueW
, TrueType
);
3156 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
3157 path
= wine_get_dos_file_name( buffer
);
3158 HeapFree( GetProcessHeap(), 0, buffer
);
3162 else if ((file
= strrchrW(face
->file
, '/')))
3167 len
= strlenW(file
) + 1;
3168 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3169 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3170 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3172 HeapFree(GetProcessHeap(), 0, path
);
3173 HeapFree(GetProcessHeap(), 0, valueW
);
3177 if(external_key
) RegCloseKey(external_key
);
3178 if(win9x_key
) RegCloseKey(win9x_key
);
3179 if(winnt_key
) RegCloseKey(winnt_key
);
3182 static void delete_external_font_keys(void)
3184 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3185 DWORD dlen
, plen
, vlen
, datalen
, valuelen
, i
, type
, path_type
;
3190 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3191 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3192 ERR("Can't create Windows font reg key\n");
3196 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3197 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3198 ERR("Can't create Windows font reg key\n");
3202 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
3203 ERR("Can't create external font reg key\n");
3207 /* Delete all external fonts added last time */
3209 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3210 &valuelen
, &datalen
, NULL
, NULL
);
3211 valuelen
++; /* returned value doesn't include room for '\0' */
3212 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3213 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
3214 path
= HeapAlloc(GetProcessHeap(), 0, datalen
);
3219 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
3220 &dlen
) == ERROR_SUCCESS
) {
3222 if (RegQueryValueExW(winnt_key
, valueW
, 0, &path_type
, path
, &plen
) == ERROR_SUCCESS
&&
3223 type
== path_type
&& dlen
== plen
&& !memcmp(data
, path
, plen
))
3224 RegDeleteValueW(winnt_key
, valueW
);
3227 if (RegQueryValueExW(win9x_key
, valueW
, 0, &path_type
, path
, &plen
) == ERROR_SUCCESS
&&
3228 type
== path_type
&& dlen
== plen
&& !memcmp(data
, path
, plen
))
3229 RegDeleteValueW(win9x_key
, valueW
);
3231 /* reset dlen and vlen */
3235 HeapFree(GetProcessHeap(), 0, path
);
3236 HeapFree(GetProcessHeap(), 0, data
);
3237 HeapFree(GetProcessHeap(), 0, valueW
);
3239 /* Delete the old external fonts key */
3240 RegCloseKey(external_key
);
3241 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
3244 if(win9x_key
) RegCloseKey(win9x_key
);
3245 if(winnt_key
) RegCloseKey(winnt_key
);
3248 /*************************************************************
3249 * WineEngAddFontResourceEx
3252 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3258 if (ft_handle
) /* do it only if we have freetype up and running */
3262 EnterCriticalSection( &freetype_cs
);
3264 if((unixname
= wine_get_unix_file_name(file
)))
3266 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3268 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3269 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
3270 HeapFree(GetProcessHeap(), 0, unixname
);
3272 if (!ret
&& !strchrW(file
, '\\')) {
3273 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3274 if ((unixname
= get_winfonts_dir_path( file
)))
3276 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3277 HeapFree(GetProcessHeap(), 0, unixname
);
3279 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3280 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3282 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3283 HeapFree(GetProcessHeap(), 0, unixname
);
3287 LeaveCriticalSection( &freetype_cs
);
3292 /*************************************************************
3293 * WineEngAddFontMemResourceEx
3296 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3300 if (ft_handle
) /* do it only if we have freetype up and running */
3302 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
3304 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
3305 memcpy(pFontCopy
, pbFont
, cbFont
);
3307 EnterCriticalSection( &freetype_cs
);
3308 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3309 LeaveCriticalSection( &freetype_cs
);
3313 TRACE("AddFontToList failed\n");
3314 HeapFree(GetProcessHeap(), 0, pFontCopy
);
3317 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3318 * For now return something unique but quite random
3320 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
3321 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
3328 /*************************************************************
3329 * WineEngRemoveFontResourceEx
3332 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3338 if (ft_handle
) /* do it only if we have freetype up and running */
3342 EnterCriticalSection( &freetype_cs
);
3344 if ((unixname
= wine_get_unix_file_name(file
)))
3346 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3348 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3349 ret
= remove_font_resource( unixname
, addfont_flags
);
3350 HeapFree(GetProcessHeap(), 0, unixname
);
3352 if (!ret
&& !strchrW(file
, '\\'))
3354 if ((unixname
= get_winfonts_dir_path( file
)))
3356 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3357 HeapFree(GetProcessHeap(), 0, unixname
);
3359 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3361 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3362 HeapFree(GetProcessHeap(), 0, unixname
);
3366 LeaveCriticalSection( &freetype_cs
);
3371 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3377 if (!font_file
) return NULL
;
3379 file_len
= strlenW( font_file
);
3381 if (font_path
&& font_path
[0])
3383 int path_len
= strlenW( font_path
);
3384 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3385 if (!fullname
) return NULL
;
3386 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3387 fullname
[path_len
] = '\\';
3388 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3392 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3393 if (!len
) return NULL
;
3394 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3395 if (!fullname
) return NULL
;
3396 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3399 unix_name
= wine_get_unix_file_name( fullname
);
3400 HeapFree( GetProcessHeap(), 0, fullname
);
3404 #include <pshpack1.h>
3407 WORD num_of_resources
;
3411 CHAR dfCopyright
[60];
3417 WORD dfInternalLeading
;
3418 WORD dfExternalLeading
;
3426 BYTE dfPitchAndFamily
;
3437 CHAR szFaceName
[LF_FACESIZE
];
3440 #include <poppack.h>
3442 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3443 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3445 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3447 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3449 WCHAR
*name
, *english_name
;
3451 NEWTEXTMETRICEXW ntm
;
3454 if (!ft_face
) return FALSE
;
3455 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3456 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3457 pFT_Done_Face( ft_face
);
3459 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3460 release_face( face
);
3461 HeapFree( GetProcessHeap(), 0, name
);
3462 HeapFree( GetProcessHeap(), 0, english_name
);
3464 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3466 memset( fd
, 0, sizeof(*fd
) );
3468 fd
->num_of_resources
= 1;
3470 fd
->dfVersion
= 0x200;
3471 fd
->dfSize
= sizeof(*fd
);
3472 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3473 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3474 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3476 fd
->dfHorizRes
= 72;
3477 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3478 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3479 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3480 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3481 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3482 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3483 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3484 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3486 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3487 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3488 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3489 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3490 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3491 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3492 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3493 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3494 fd
->dfWidthBytes
= 0;
3496 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3498 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3503 #define NE_FFLAGS_LIBMODULE 0x8000
3504 #define NE_OSFLAGS_WINDOWS 0x02
3506 static const char dos_string
[0x40] = "This is a TrueType resource file";
3507 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3509 #include <pshpack2.h>
3530 struct ne_typeinfo fontdir_type
;
3531 struct ne_nameinfo fontdir_name
;
3532 struct ne_typeinfo scalable_type
;
3533 struct ne_nameinfo scalable_name
;
3535 BYTE fontdir_res_name
[8];
3538 #include <poppack.h>
3540 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3544 DWORD size
, written
;
3546 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3547 char *font_fileA
, *last_part
, *ext
;
3548 IMAGE_DOS_HEADER dos
;
3549 IMAGE_OS2_HEADER ne
=
3551 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3553 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3554 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3556 struct rsrc_tab rsrc_tab
=
3560 { 0, 0, 0x0c50, 0x2c, 0 },
3562 { 0, 0, 0x0c50, 0x8001, 0 },
3564 { 7,'F','O','N','T','D','I','R'}
3567 memset( &dos
, 0, sizeof(dos
) );
3568 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3569 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3571 /* import name is last part\0, resident name is last part without extension
3572 non-resident name is "FONTRES:" + lfFaceName */
3574 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3575 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3576 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3578 last_part
= strrchr( font_fileA
, '\\' );
3579 if (last_part
) last_part
++;
3580 else last_part
= font_fileA
;
3581 import_name_len
= strlen( last_part
) + 1;
3583 ext
= strchr( last_part
, '.' );
3584 if (ext
) res_name_len
= ext
- last_part
;
3585 else res_name_len
= import_name_len
- 1;
3587 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3589 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3590 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3591 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3592 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3594 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3596 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3597 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3598 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3599 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3601 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3602 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3606 HeapFree( GetProcessHeap(), 0, font_fileA
);
3610 memcpy( ptr
, &dos
, sizeof(dos
) );
3611 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3612 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3614 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3615 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3617 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3618 *ptr
++ = res_name_len
;
3619 memcpy( ptr
, last_part
, res_name_len
);
3621 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3622 *ptr
++ = import_name_len
;
3623 memcpy( ptr
, last_part
, import_name_len
);
3625 ptr
= start
+ ne
.ne_nrestab
;
3626 *ptr
++ = non_res_name_len
;
3627 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3628 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3630 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3631 memcpy( ptr
, font_fileA
, font_file_len
);
3633 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3634 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3636 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3637 if (file
!= INVALID_HANDLE_VALUE
)
3639 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3641 CloseHandle( file
);
3644 HeapFree( GetProcessHeap(), 0, start
);
3645 HeapFree( GetProcessHeap(), 0, font_fileA
);
3650 /*************************************************************
3651 * WineEngCreateScalableFontResource
3654 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3655 LPCWSTR font_file
, LPCWSTR font_path
)
3657 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3658 struct fontdir fontdir
;
3661 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3662 SetLastError( ERROR_INVALID_PARAMETER
);
3665 if (hidden
) fontdir
.dfType
|= 0x80;
3666 ret
= create_fot( resource
, font_file
, &fontdir
);
3669 HeapFree( GetProcessHeap(), 0, unix_name
);
3673 static const struct nls_update_font_list
3675 UINT ansi_cp
, oem_cp
;
3676 const char *oem
, *fixed
, *system
;
3677 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3678 /* these are for font substitutes */
3679 const char *shelldlg
, *tmsrmn
;
3680 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3684 const char *from
, *to
;
3685 } arial_0
, courier_new_0
, times_new_roman_0
;
3686 } nls_update_font_list
[] =
3688 /* Latin 1 (United States) */
3689 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3690 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3691 "Tahoma","Times New Roman",
3692 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3695 /* Latin 1 (Multilingual) */
3696 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3697 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3698 "Tahoma","Times New Roman", /* FIXME unverified */
3699 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3702 /* Eastern Europe */
3703 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3704 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3705 "Tahoma","Times New Roman", /* FIXME unverified */
3706 "Fixedsys,238", "System,238",
3707 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3708 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3709 { "Arial CE,0", "Arial,238" },
3710 { "Courier New CE,0", "Courier New,238" },
3711 { "Times New Roman CE,0", "Times New Roman,238" }
3714 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3715 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3716 "Tahoma","Times New Roman", /* FIXME unverified */
3717 "Fixedsys,204", "System,204",
3718 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3719 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3720 { "Arial Cyr,0", "Arial,204" },
3721 { "Courier New Cyr,0", "Courier New,204" },
3722 { "Times New Roman Cyr,0", "Times New Roman,204" }
3725 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3726 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3727 "Tahoma","Times New Roman", /* FIXME unverified */
3728 "Fixedsys,161", "System,161",
3729 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3730 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3731 { "Arial Greek,0", "Arial,161" },
3732 { "Courier New Greek,0", "Courier New,161" },
3733 { "Times New Roman Greek,0", "Times New Roman,161" }
3736 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3737 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3738 "Tahoma","Times New Roman", /* FIXME unverified */
3739 "Fixedsys,162", "System,162",
3740 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3741 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3742 { "Arial Tur,0", "Arial,162" },
3743 { "Courier New Tur,0", "Courier New,162" },
3744 { "Times New Roman Tur,0", "Times New Roman,162" }
3747 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3748 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3749 "Tahoma","Times New Roman", /* FIXME unverified */
3750 "Fixedsys,177", "System,177",
3751 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3752 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3756 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3757 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3758 "Microsoft Sans Serif","Times New Roman",
3759 "Fixedsys,178", "System,178",
3760 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3761 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3765 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3766 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3767 "Tahoma","Times New Roman", /* FIXME unverified */
3768 "Fixedsys,186", "System,186",
3769 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3770 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3771 { "Arial Baltic,0", "Arial,186" },
3772 { "Courier New Baltic,0", "Courier New,186" },
3773 { "Times New Roman Baltic,0", "Times New Roman,186" }
3776 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3777 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3778 "Tahoma","Times New Roman", /* FIXME unverified */
3779 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3783 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3784 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3785 "Tahoma","Times New Roman", /* FIXME unverified */
3786 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3790 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3791 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3792 "MS UI Gothic","MS Serif",
3793 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3796 /* Chinese Simplified */
3797 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3798 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3799 "SimSun", "NSimSun",
3800 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3804 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3805 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3807 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3810 /* Chinese Traditional */
3811 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3812 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3813 "PMingLiU", "MingLiU",
3814 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3819 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3821 return ( ansi_cp
== 932 /* CP932 for Japanese */
3822 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3823 || ansi_cp
== 949 /* CP949 for Korean */
3824 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3827 static inline HKEY
create_fonts_NT_registry_key(void)
3831 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3832 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3836 static inline HKEY
create_fonts_9x_registry_key(void)
3840 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3841 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3845 static inline HKEY
create_config_fonts_registry_key(void)
3849 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3850 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3854 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3856 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3858 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3859 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3860 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3861 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3864 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3867 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3869 RegDeleteValueA(hkey
, name
);
3872 static void update_font_association_info(UINT current_ansi_codepage
)
3874 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3875 static const char *assoc_charset_subkey
= "Associated Charset";
3877 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3880 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3883 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3885 switch (current_ansi_codepage
)
3888 set_value_key(hsubkey
, "ANSI(00)", "NO");
3889 set_value_key(hsubkey
, "OEM(FF)", "NO");
3890 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3895 set_value_key(hsubkey
, "ANSI(00)", "YES");
3896 set_value_key(hsubkey
, "OEM(FF)", "YES");
3897 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3900 RegCloseKey(hsubkey
);
3903 /* TODO: Associated DefaultFonts */
3909 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3912 static void set_multi_value_key(HKEY hkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD len
)
3915 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (const BYTE
*)value
, len
);
3917 RegDeleteValueW(hkey
, name
);
3920 static void update_font_system_link_info(UINT current_ansi_codepage
)
3922 static const WCHAR system_link_simplified_chinese
[] =
3923 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3924 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3925 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3926 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3928 static const WCHAR system_link_traditional_chinese
[] =
3929 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
3930 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3931 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3932 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
3934 static const WCHAR system_link_japanese
[] =
3935 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3936 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3937 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3938 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3940 static const WCHAR system_link_korean
[] =
3941 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3942 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3943 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3944 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3946 static const WCHAR system_link_non_cjk
[] =
3947 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
3948 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
3949 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
3950 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
3954 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
3959 switch (current_ansi_codepage
)
3962 link
= system_link_japanese
;
3963 len
= sizeof(system_link_japanese
);
3966 link
= system_link_simplified_chinese
;
3967 len
= sizeof(system_link_simplified_chinese
);
3970 link
= system_link_korean
;
3971 len
= sizeof(system_link_korean
);
3974 link
= system_link_traditional_chinese
;
3975 len
= sizeof(system_link_traditional_chinese
);
3978 link
= system_link_non_cjk
;
3979 len
= sizeof(system_link_non_cjk
);
3981 set_multi_value_key(hkey
, Lucida_Sans_Unicode
, link
, len
);
3982 set_multi_value_key(hkey
, Microsoft_Sans_Serif
, link
, len
);
3983 set_multi_value_key(hkey
, Tahoma
, link
, len
);
3988 static void update_font_info(void)
3990 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3991 char buf
[40], cpbuf
[40];
3994 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3995 DWORD screen_dpi
, font_dpi
= 0;
3998 screen_dpi
= get_dpi();
3999 if (!screen_dpi
) screen_dpi
= 96;
4001 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
4004 reg_load_dword(hkey
, logpixels
, &font_dpi
);
4006 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
4007 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
4008 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
4009 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
4010 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
4012 /* Setup Default_Fallback usage for DBCS ANSI codepages */
4013 if (is_dbcs_ansi_cp(ansi_cp
))
4014 use_default_fallback
= TRUE
;
4018 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
4020 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
4025 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
4026 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
4028 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
4029 ansi_cp
, oem_cp
, screen_dpi
);
4031 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
4032 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
4035 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
4039 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
4040 nls_update_font_list
[i
].oem_cp
== oem_cp
)
4042 hkey
= create_config_fonts_registry_key();
4043 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
4044 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
4045 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
4048 hkey
= create_fonts_NT_registry_key();
4049 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
4052 hkey
= create_fonts_9x_registry_key();
4053 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
4056 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
4058 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
4059 strlen(nls_update_font_list
[i
].shelldlg
)+1);
4060 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
4061 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
4063 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
4064 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
4065 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
4066 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
4067 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
4068 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
4069 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
4070 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
4072 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
4073 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
4074 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
4082 /* Delete the FontSubstitutes from other locales */
4083 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
4085 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
4086 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
4087 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
4093 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
4095 /* update locale dependent font association info and font system link info in registry.
4096 update only when codepages changed, not logpixels. */
4097 if (strcmp(buf
, cpbuf
) != 0)
4099 update_font_association_info(ansi_cp
);
4100 update_font_system_link_info(ansi_cp
);
4104 static BOOL
init_freetype(void)
4106 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
4109 "Wine cannot find the FreeType font library. To enable Wine to\n"
4110 "use TrueType fonts please install a version of FreeType greater than\n"
4111 "or equal to 2.0.5.\n"
4112 "http://www.freetype.org\n");
4116 #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;}
4118 LOAD_FUNCPTR(FT_Done_Face
)
4119 LOAD_FUNCPTR(FT_Get_Char_Index
)
4120 LOAD_FUNCPTR(FT_Get_First_Char
)
4121 LOAD_FUNCPTR(FT_Get_Next_Char
)
4122 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
4123 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
4124 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
4125 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
4126 LOAD_FUNCPTR(FT_Init_FreeType
)
4127 LOAD_FUNCPTR(FT_Library_Version
)
4128 LOAD_FUNCPTR(FT_Load_Glyph
)
4129 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
4130 LOAD_FUNCPTR(FT_Matrix_Multiply
)
4131 #ifndef FT_MULFIX_INLINED
4132 LOAD_FUNCPTR(FT_MulFix
)
4134 LOAD_FUNCPTR(FT_New_Face
)
4135 LOAD_FUNCPTR(FT_New_Memory_Face
)
4136 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
4137 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
4138 LOAD_FUNCPTR(FT_Outline_Transform
)
4139 LOAD_FUNCPTR(FT_Outline_Translate
)
4140 LOAD_FUNCPTR(FT_Render_Glyph
)
4141 LOAD_FUNCPTR(FT_Set_Charmap
)
4142 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
4143 LOAD_FUNCPTR(FT_Vector_Length
)
4144 LOAD_FUNCPTR(FT_Vector_Transform
)
4145 LOAD_FUNCPTR(FT_Vector_Unit
)
4147 /* Don't warn if these ones are missing */
4148 pFT_Outline_Embolden
= wine_dlsym(ft_handle
, "FT_Outline_Embolden", NULL
, 0);
4149 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
4150 #ifdef FT_LCD_FILTER_H
4151 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
4154 if(pFT_Init_FreeType(&library
) != 0) {
4155 ERR("Can't init FreeType library\n");
4156 wine_dlclose(ft_handle
, NULL
, 0);
4160 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
4162 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
4163 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
4164 ((FT_Version
.minor
<< 8) & 0x00ff00) |
4165 ((FT_Version
.patch
) & 0x0000ff);
4167 font_driver
= &freetype_funcs
;
4172 "Wine cannot find certain functions that it needs inside the FreeType\n"
4173 "font library. To enable Wine to use TrueType fonts please upgrade\n"
4174 "FreeType to at least version 2.1.4.\n"
4175 "http://www.freetype.org\n");
4176 wine_dlclose(ft_handle
, NULL
, 0);
4181 static void init_font_list(void)
4183 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
4184 static const WCHAR pathW
[] = {'P','a','t','h',0};
4186 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
4187 WCHAR windowsdir
[MAX_PATH
];
4190 delete_external_font_keys();
4192 /* load the system bitmap fonts */
4193 load_system_fonts();
4195 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
4196 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
4197 strcatW(windowsdir
, fontsW
);
4198 if((unixname
= wine_get_unix_file_name(windowsdir
)))
4200 ReadFontDir(unixname
, FALSE
);
4201 HeapFree(GetProcessHeap(), 0, unixname
);
4204 /* load the wine fonts */
4205 if ((unixname
= get_font_dir()))
4207 ReadFontDir(unixname
, TRUE
);
4208 HeapFree(GetProcessHeap(), 0, unixname
);
4211 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4212 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4213 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4215 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
4216 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
4217 &hkey
) == ERROR_SUCCESS
)
4219 LPWSTR data
, valueW
;
4220 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4221 &valuelen
, &datalen
, NULL
, NULL
);
4223 valuelen
++; /* returned value doesn't include room for '\0' */
4224 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
4225 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
4228 dlen
= datalen
* sizeof(WCHAR
);
4230 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
4231 &dlen
) == ERROR_SUCCESS
)
4233 if(data
[0] && (data
[1] == ':'))
4235 if((unixname
= wine_get_unix_file_name(data
)))
4237 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4238 HeapFree(GetProcessHeap(), 0, unixname
);
4241 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
4243 WCHAR pathW
[MAX_PATH
];
4244 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
4247 sprintfW(pathW
, fmtW
, windowsdir
, data
);
4248 if((unixname
= wine_get_unix_file_name(pathW
)))
4250 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4251 HeapFree(GetProcessHeap(), 0, unixname
);
4254 load_font_from_data_dir(data
);
4256 /* reset dlen and vlen */
4261 HeapFree(GetProcessHeap(), 0, data
);
4262 HeapFree(GetProcessHeap(), 0, valueW
);
4266 #ifdef SONAME_LIBFONTCONFIG
4267 load_fontconfig_fonts();
4268 #elif defined(HAVE_CARBON_CARBON_H)
4270 #elif defined(__ANDROID__)
4271 ReadFontDir("/system/fonts", TRUE
);
4274 /* then look in any directories that we've specified in the config file */
4275 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4276 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
4282 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
4284 len
+= sizeof(WCHAR
);
4285 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
4286 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
4288 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
4289 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
4290 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
4291 TRACE( "got font path %s\n", debugstr_a(valueA
) );
4296 LPSTR next
= strchr( ptr
, ':' );
4297 if (next
) *next
++ = 0;
4298 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
4299 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
4301 strcpy( unixname
, home
);
4302 strcat( unixname
, ptr
+ 1 );
4303 ReadFontDir( unixname
, TRUE
);
4304 HeapFree( GetProcessHeap(), 0, unixname
);
4307 ReadFontDir( ptr
, TRUE
);
4310 HeapFree( GetProcessHeap(), 0, valueA
);
4312 HeapFree( GetProcessHeap(), 0, valueW
);
4318 static BOOL
move_to_front(const WCHAR
*name
)
4320 Family
*family
, *cursor2
;
4321 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
4323 if(!strcmpiW(family
->FamilyName
, name
))
4325 list_remove(&family
->entry
);
4326 list_add_head(&font_list
, &family
->entry
);
4333 static BOOL
set_default(const WCHAR
**name_list
)
4337 if (move_to_front(*name_list
)) return TRUE
;
4344 static void reorder_font_list(void)
4346 set_default( default_serif_list
);
4347 set_default( default_fixed_list
);
4348 set_default( default_sans_list
);
4351 /*************************************************************
4354 * Initialize FreeType library and create a list of available faces
4356 BOOL
WineEngInit(void)
4362 /* update locale dependent font info in registry */
4365 if(!init_freetype()) return FALSE
;
4367 #ifdef SONAME_LIBFONTCONFIG
4371 if (!RegOpenKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, KEY_READ
, &hkey
))
4373 static const WCHAR antialias_fake_bold_or_italic
[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
4374 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
4375 static const WCHAR true_options
[] = { 'y','Y','t','T','1',0 };
4379 size
= sizeof(buffer
);
4380 if (!RegQueryValueExW(hkey
, antialias_fake_bold_or_italic
, NULL
, &type
, (BYTE
*)buffer
, &size
) &&
4381 type
== REG_SZ
&& size
>= 1)
4383 antialias_fakes
= (strchrW(true_options
, buffer
[0]) != NULL
);
4388 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
4390 ERR("Failed to create font mutex\n");
4393 WaitForSingleObject(font_mutex
, INFINITE
);
4395 create_font_cache_key(&hkey_font_cache
, &disposition
);
4397 if(disposition
== REG_CREATED_NEW_KEY
)
4400 load_font_list_from_cache(hkey_font_cache
);
4402 reorder_font_list();
4409 if(disposition
== REG_CREATED_NEW_KEY
)
4410 update_reg_entries();
4412 init_system_links();
4414 ReleaseMutex(font_mutex
);
4418 /* Some fonts have large usWinDescent values, as a result of storing signed short
4419 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4420 some font generation tools. */
4421 static inline USHORT
get_fixed_windescent(USHORT windescent
)
4423 return abs((SHORT
)windescent
);
4426 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
4429 TT_HoriHeader
*pHori
;
4432 const LONG MAX_PPEM
= (1 << 16) - 1;
4434 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4435 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4437 if(height
== 0) height
= 16;
4439 /* Calc. height of EM square:
4441 * For +ve lfHeight we have
4442 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4443 * Re-arranging gives:
4444 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4446 * For -ve lfHeight we have
4448 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4449 * with il = winAscent + winDescent - units_per_em]
4454 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
4455 if(pOS2
->usWinAscent
+ windescent
== 0)
4456 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4457 pHori
->Ascender
- pHori
->Descender
);
4459 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4460 pOS2
->usWinAscent
+ windescent
);
4461 if(ppem
> MAX_PPEM
) {
4462 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4466 else if(height
>= -MAX_PPEM
)
4469 WARN("Ignoring too large height %d\n", height
);
4476 static struct font_mapping
*map_font_file( const char *name
)
4478 struct font_mapping
*mapping
;
4482 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4483 if (fstat( fd
, &st
) == -1) goto error
;
4485 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4487 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4489 mapping
->refcount
++;
4494 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4497 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4500 if (mapping
->data
== MAP_FAILED
)
4502 HeapFree( GetProcessHeap(), 0, mapping
);
4505 mapping
->refcount
= 1;
4506 mapping
->dev
= st
.st_dev
;
4507 mapping
->ino
= st
.st_ino
;
4508 mapping
->size
= st
.st_size
;
4509 list_add_tail( &mappings_list
, &mapping
->entry
);
4517 static void unmap_font_file( struct font_mapping
*mapping
)
4519 if (!--mapping
->refcount
)
4521 list_remove( &mapping
->entry
);
4522 munmap( mapping
->data
, mapping
->size
);
4523 HeapFree( GetProcessHeap(), 0, mapping
);
4527 static LONG
load_VDMX(GdiFont
*, LONG
);
4529 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4536 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4540 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4541 font
->mapping
= map_font_file( filename
);
4542 HeapFree( GetProcessHeap(), 0, filename
);
4545 WARN("failed to map %s\n", debugstr_w(face
->file
));
4548 data_ptr
= font
->mapping
->data
;
4549 data_size
= font
->mapping
->size
;
4553 data_ptr
= face
->font_data_ptr
;
4554 data_size
= face
->font_data_size
;
4557 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4559 ERR("FT_New_Face rets %d\n", err
);
4563 /* set it here, as load_VDMX needs it */
4564 font
->ft_face
= ft_face
;
4566 if(FT_IS_SCALABLE(ft_face
)) {
4570 /* load the VDMX table if we have one */
4571 font
->ppem
= load_VDMX(font
, height
);
4573 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4574 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4576 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4577 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4579 /* see if it's a TTC */
4580 len
= sizeof(header
);
4581 if (!pFT_Load_Sfnt_Table(ft_face
, 0, 0, (void*)&header
, &len
)) {
4582 if (header
== MS_TTCF_TAG
)
4584 len
= sizeof(font
->ttc_item_offset
);
4585 if (pFT_Load_Sfnt_Table(ft_face
, 0, (3 + face
->face_index
) * sizeof(DWORD
),
4586 (void*)&font
->ttc_item_offset
, &len
))
4587 font
->ttc_item_offset
= 0;
4589 font
->ttc_item_offset
= GET_BE_DWORD(font
->ttc_item_offset
);
4593 font
->ppem
= height
;
4594 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4595 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4601 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4603 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4604 a single face with the requested charset. The idea is to check if
4605 the selected font supports the current ANSI codepage, if it does
4606 return the corresponding charset, else return the first charset */
4609 int acp
= GetACP(), i
;
4613 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4615 const SYSTEM_LINKS
*font_link
;
4617 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4618 return csi
.ciCharset
;
4620 font_link
= find_font_link(family_name
);
4621 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4622 return csi
.ciCharset
;
4625 for(i
= 0; i
< 32; i
++) {
4627 if(face
->fs
.fsCsb
[0] & fs0
) {
4628 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4630 return csi
.ciCharset
;
4633 FIXME("TCI failing on %x\n", fs0
);
4637 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4638 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4640 return DEFAULT_CHARSET
;
4643 static GdiFont
*alloc_font(void)
4645 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4648 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4649 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4651 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4652 ret
->total_kern_pairs
= (DWORD
)-1;
4653 ret
->kern_pairs
= NULL
;
4654 ret
->instance_id
= alloc_font_handle(ret
);
4655 list_init(&ret
->child_fonts
);
4659 static void free_font(GdiFont
*font
)
4661 CHILD_FONT
*child
, *child_next
;
4664 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4666 list_remove(&child
->entry
);
4668 free_font(child
->font
);
4669 release_face( child
->face
);
4670 HeapFree(GetProcessHeap(), 0, child
);
4673 HeapFree(GetProcessHeap(), 0, font
->fileinfo
);
4674 free_font_handle(font
->instance_id
);
4675 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4676 if (font
->mapping
) unmap_font_file( font
->mapping
);
4677 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4678 HeapFree(GetProcessHeap(), 0, font
->potm
);
4679 HeapFree(GetProcessHeap(), 0, font
->name
);
4680 for (i
= 0; i
< font
->gmsize
; i
++)
4681 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4682 HeapFree(GetProcessHeap(), 0, font
->gm
);
4683 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4684 HeapFree(GetProcessHeap(), 0, font
);
4688 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4690 FT_Face ft_face
= font
->ft_face
;
4694 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4701 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
4702 0 tag means to read from start of collection member data. */
4703 if (font
->ttc_item_offset
)
4705 if (table
== MS_TTCF_TAG
)
4707 else if (table
== 0)
4708 offset
+= font
->ttc_item_offset
;
4711 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4713 /* make sure value of len is the value freetype says it needs */
4716 FT_ULong needed
= 0;
4717 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4718 if( !err
&& needed
< len
) len
= needed
;
4720 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4723 table
= RtlUlongByteSwap( table
);
4724 TRACE("Can't find table %s\n", debugstr_an((char*)&table
, 4));
4730 /*************************************************************
4733 * load the vdmx entry for the specified height
4763 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4767 BYTE devXRatio
, devYRatio
;
4768 USHORT numRecs
, numRatios
;
4769 DWORD result
, offset
= -1;
4773 result
= get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
4775 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4778 /* FIXME: need the real device aspect ratio */
4782 numRecs
= GET_BE_WORD(hdr
.numRecs
);
4783 numRatios
= GET_BE_WORD(hdr
.numRatios
);
4785 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
4786 for(i
= 0; i
< numRatios
; i
++) {
4789 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
4790 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4793 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4795 if (!ratio
.bCharSet
) continue;
4797 if((ratio
.xRatio
== 0 &&
4798 ratio
.yStartRatio
== 0 &&
4799 ratio
.yEndRatio
== 0) ||
4800 (devXRatio
== ratio
.xRatio
&&
4801 devYRatio
>= ratio
.yStartRatio
&&
4802 devYRatio
<= ratio
.yEndRatio
))
4806 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
4807 get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
4808 offset
= GET_BE_WORD(group_offset
);
4813 if(offset
== -1) return 0;
4815 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
4817 BYTE startsz
, endsz
;
4820 recs
= GET_BE_WORD(group
.recs
);
4821 startsz
= group
.startsz
;
4822 endsz
= group
.endsz
;
4824 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4826 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
4827 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
4828 if(result
== GDI_ERROR
) {
4829 FIXME("Failed to retrieve vTable\n");
4834 for(i
= 0; i
< recs
; i
++) {
4835 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4836 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4837 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4839 if(yMax
+ -yMin
== height
) {
4842 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4845 if(yMax
+ -yMin
> height
) {
4848 goto end
; /* failed */
4850 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4851 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4852 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4853 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4859 TRACE("ppem not found for height %d\n", height
);
4863 if(ppem
< startsz
|| ppem
> endsz
)
4869 for(i
= 0; i
< recs
; i
++) {
4871 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4873 if(yPelHeight
> ppem
)
4879 if(yPelHeight
== ppem
) {
4880 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4881 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4882 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4888 HeapFree(GetProcessHeap(), 0, vTable
);
4894 static void dump_gdi_font_list(void)
4898 TRACE("---------- Font Cache ----------\n");
4899 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4900 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4901 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4904 static void grab_font( GdiFont
*font
)
4906 if (!font
->refcount
++)
4908 list_remove( &font
->unused_entry
);
4909 unused_font_count
--;
4913 static void release_font( GdiFont
*font
)
4916 if (!--font
->refcount
)
4918 TRACE( "font %p\n", font
);
4920 /* add it to the unused list */
4921 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4922 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4924 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4925 TRACE( "freeing %p\n", font
);
4926 list_remove( &font
->entry
);
4927 list_remove( &font
->unused_entry
);
4930 else unused_font_count
++;
4932 if (TRACE_ON(font
)) dump_gdi_font_list();
4936 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4938 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4939 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4940 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4941 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4942 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4945 static void calc_hash(FONT_DESC
*pfd
)
4947 DWORD hash
= 0, *ptr
, two_chars
;
4951 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4953 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4955 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4957 pwc
= (WCHAR
*)&two_chars
;
4959 *pwc
= toupperW(*pwc
);
4961 *pwc
= toupperW(*pwc
);
4965 hash
^= !pfd
->can_use_bitmap
;
4969 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4976 fd
.can_use_bitmap
= can_use_bitmap
;
4979 /* try the in-use list */
4980 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4982 if(fontcmp(ret
, &fd
)) continue;
4983 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4984 list_remove( &ret
->entry
);
4985 list_add_head( &gdi_font_list
, &ret
->entry
);
4992 static void add_to_cache(GdiFont
*font
)
4994 static DWORD cache_num
= 1;
4996 font
->cache_num
= cache_num
++;
4997 list_add_head(&gdi_font_list
, &font
->entry
);
4998 TRACE( "font %p\n", font
);
5001 /*************************************************************
5002 * create_child_font_list
5004 static BOOL
create_child_font_list(GdiFont
*font
)
5007 SYSTEM_LINKS
*font_link
;
5008 CHILD_FONT
*font_link_entry
, *new_child
;
5012 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
5013 font_name
= psub
? psub
->to
.name
: font
->name
;
5014 font_link
= find_font_link(font_name
);
5015 if (font_link
!= NULL
)
5017 TRACE("found entry in system list\n");
5018 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5020 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
5021 new_child
->face
= font_link_entry
->face
;
5022 new_child
->font
= NULL
;
5023 new_child
->face
->refcount
++;
5024 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
5025 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
5030 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
5031 * Sans Serif. This is how asian windows get default fallbacks for fonts
5033 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
5034 font
->charset
!= OEM_CHARSET
&&
5035 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
5037 font_link
= find_font_link(szDefaultFallbackLink
);
5038 if (font_link
!= NULL
)
5040 TRACE("found entry in default fallback list\n");
5041 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5043 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
5044 new_child
->face
= font_link_entry
->face
;
5045 new_child
->font
= NULL
;
5046 new_child
->face
->refcount
++;
5047 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
5048 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
5057 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
5059 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
5060 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
5063 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
5065 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
5067 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
5069 TRACE("found cmap with platform_id %u, encoding_id %u\n",
5070 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
5072 switch (ft_face
->charmaps
[i
]->platform_id
)
5075 cmap_def
= ft_face
->charmaps
[i
];
5077 case 0: /* Apple Unicode */
5078 cmap0
= ft_face
->charmaps
[i
];
5080 case 1: /* Macintosh */
5081 cmap1
= ft_face
->charmaps
[i
];
5084 cmap2
= ft_face
->charmaps
[i
];
5086 case 3: /* Microsoft */
5087 cmap3
= ft_face
->charmaps
[i
];
5092 if (cmap3
) /* prefer Microsoft cmap table */
5093 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
5095 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
5097 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
5099 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
5101 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
5104 return ft_err
== FT_Err_Ok
;
5108 /*************************************************************
5111 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
5112 LPCWSTR output
, const DEVMODEW
*devmode
)
5114 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
5116 if (!physdev
) return FALSE
;
5117 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
5122 /*************************************************************
5125 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
5127 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5128 release_font( physdev
->font
);
5129 HeapFree( GetProcessHeap(), 0, physdev
);
5133 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
5135 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
5136 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
5137 const FT_Encoding
*encs
= regular_order
;
5139 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
5143 if (select_charmap( face
, *encs
)) break;
5149 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
5152 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
5153 WORD
*alloced
= NULL
, *ptr
= buf
;
5154 WORD num_recs
, version
;
5158 size
= get_font_data( font
, MS_GASP_TAG
, 0, NULL
, 0 );
5159 if (size
== GDI_ERROR
) return FALSE
;
5160 if (size
< 4 * sizeof(WORD
)) return FALSE
;
5161 if (size
> sizeof(buf
))
5163 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
5164 if (!ptr
) return FALSE
;
5167 get_font_data( font
, MS_GASP_TAG
, 0, ptr
, size
);
5169 version
= GET_BE_WORD( *ptr
++ );
5170 num_recs
= GET_BE_WORD( *ptr
++ );
5172 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
5174 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
5180 *flags
= GET_BE_WORD( *(ptr
+ 1) );
5181 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
5184 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
5188 HeapFree( GetProcessHeap(), 0, alloced
);
5192 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5194 const GSUB_ScriptList
*script
;
5195 const GSUB_Script
*deflt
= NULL
;
5197 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5199 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5200 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5202 const GSUB_Script
*scr
;
5205 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5206 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5208 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5210 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5216 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5220 const GSUB_LangSys
*Lang
;
5222 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5224 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5226 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5227 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5229 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5232 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5235 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5241 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5244 const GSUB_FeatureList
*feature
;
5245 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5247 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5248 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5250 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5251 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5253 const GSUB_Feature
*feat
;
5254 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5261 static const char* get_opentype_script(const GdiFont
*font
)
5264 * I am not sure if this is the correct way to generate our script tag
5267 switch (font
->charset
)
5269 case ANSI_CHARSET
: return "latn";
5270 case BALTIC_CHARSET
: return "latn"; /* ?? */
5271 case CHINESEBIG5_CHARSET
: return "hani";
5272 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5273 case GB2312_CHARSET
: return "hani";
5274 case GREEK_CHARSET
: return "grek";
5275 case HANGUL_CHARSET
: return "hang";
5276 case RUSSIAN_CHARSET
: return "cyrl";
5277 case SHIFTJIS_CHARSET
: return "kana";
5278 case TURKISH_CHARSET
: return "latn"; /* ?? */
5279 case VIETNAMESE_CHARSET
: return "latn";
5280 case JOHAB_CHARSET
: return "latn"; /* ?? */
5281 case ARABIC_CHARSET
: return "arab";
5282 case HEBREW_CHARSET
: return "hebr";
5283 case THAI_CHARSET
: return "thai";
5284 default: return "latn";
5288 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
5290 const GSUB_Header
*header
;
5291 const GSUB_Script
*script
;
5292 const GSUB_LangSys
*language
;
5293 const GSUB_Feature
*feature
;
5295 if (!font
->GSUB_Table
)
5298 header
= font
->GSUB_Table
;
5300 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5303 TRACE("Script not found\n");
5306 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5309 TRACE("Language not found\n");
5312 feature
= GSUB_get_feature(header
, language
, "vrt2");
5314 feature
= GSUB_get_feature(header
, language
, "vert");
5317 TRACE("vrt2/vert feature not found\n");
5323 static void fill_fileinfo_from_face( GdiFont
*font
, Face
*face
)
5325 WIN32_FILE_ATTRIBUTE_DATA info
;
5330 font
->fileinfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*font
->fileinfo
));
5334 len
= strlenW(face
->file
);
5335 font
->fileinfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font
->fileinfo
) + len
* sizeof(WCHAR
));
5336 if (GetFileAttributesExW(face
->file
, GetFileExInfoStandard
, &info
))
5338 font
->fileinfo
->writetime
= info
.ftLastWriteTime
;
5339 font
->fileinfo
->size
.QuadPart
= (LONGLONG
)info
.nFileSizeHigh
<< 32 | info
.nFileSizeLow
;
5340 strcpyW(font
->fileinfo
->path
, face
->file
);
5343 memset(font
->fileinfo
, 0, sizeof(*font
->fileinfo
) + len
* sizeof(WCHAR
));
5346 /*************************************************************
5347 * freetype_SelectFont
5349 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5351 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5353 Face
*face
, *best
, *best_bitmap
;
5354 Family
*family
, *last_resort_family
;
5355 const struct list
*face_list
;
5356 INT height
, width
= 0;
5357 unsigned int score
= 0, new_score
;
5358 signed int diff
= 0, newdiff
;
5359 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5363 FontSubst
*psub
= NULL
;
5364 DC
*dc
= get_physdev_dc( dev
);
5365 const SYSTEM_LINKS
*font_link
;
5367 if (!hfont
) /* notification that the font has been changed by another driver */
5369 release_font( physdev
->font
);
5370 physdev
->font
= NULL
;
5374 GetObjectW( hfont
, sizeof(lf
), &lf
);
5375 lf
.lfWidth
= abs(lf
.lfWidth
);
5377 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5379 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5380 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5381 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5384 if(dc
->GraphicsMode
== GM_ADVANCED
)
5386 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5387 /* Try to avoid not necessary glyph transformations */
5388 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5390 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5391 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5392 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5397 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5398 font scaling abilities. */
5399 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5400 dcmat
.eM21
= dcmat
.eM12
= 0;
5401 lf
.lfOrientation
= lf
.lfEscapement
;
5402 if (dc
->vport2WorldValid
)
5404 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5405 lf
.lfOrientation
= -lf
.lfOrientation
;
5406 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5407 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5411 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5412 dcmat
.eM21
, dcmat
.eM22
);
5415 EnterCriticalSection( &freetype_cs
);
5417 /* check the cache first */
5418 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5419 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5423 TRACE("not in cache\n");
5426 ret
->font_desc
.matrix
= dcmat
;
5427 ret
->font_desc
.lf
= lf
;
5428 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5429 calc_hash(&ret
->font_desc
);
5431 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5432 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5433 original value lfCharSet. Note this is a special case for
5434 Symbol and doesn't happen at least for "Wingdings*" */
5436 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5437 lf
.lfCharSet
= SYMBOL_CHARSET
;
5439 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5440 switch(lf
.lfCharSet
) {
5441 case DEFAULT_CHARSET
:
5442 csi
.fs
.fsCsb
[0] = 0;
5445 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5446 csi
.fs
.fsCsb
[0] = 0;
5452 if(lf
.lfFaceName
[0] != '\0') {
5453 CHILD_FONT
*font_link_entry
;
5454 LPWSTR FaceName
= lf
.lfFaceName
;
5456 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5459 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5460 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5461 if (psub
->to
.charset
!= -1)
5462 lf
.lfCharSet
= psub
->to
.charset
;
5465 /* We want a match on name and charset or just name if
5466 charset was DEFAULT_CHARSET. If the latter then
5467 we fixup the returned charset later in get_nearest_charset
5468 where we'll either use the charset of the current ansi codepage
5469 or if that's unavailable the first charset that the font supports.
5471 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5472 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5473 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5475 font_link
= find_font_link(family
->FamilyName
);
5476 face_list
= get_face_list_from_family(family
);
5477 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5478 if (!(face
->scalable
|| can_use_bitmap
))
5480 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5482 if (font_link
!= NULL
&&
5483 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5485 if (!csi
.fs
.fsCsb
[0])
5491 /* Search by full face name. */
5492 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5493 face_list
= get_face_list_from_family(family
);
5494 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5495 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5496 (face
->scalable
|| can_use_bitmap
))
5498 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5500 font_link
= find_font_link(family
->FamilyName
);
5501 if (font_link
!= NULL
&&
5502 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5509 * Try check the SystemLink list first for a replacement font.
5510 * We may find good replacements there.
5512 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5514 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5515 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5517 TRACE("found entry in system list\n");
5518 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5520 const SYSTEM_LINKS
*links
;
5522 face
= font_link_entry
->face
;
5523 if (!(face
->scalable
|| can_use_bitmap
))
5525 family
= face
->family
;
5526 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5528 links
= find_font_link(family
->FamilyName
);
5529 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5536 psub
= NULL
; /* substitution is no more relevant */
5538 /* If requested charset was DEFAULT_CHARSET then try using charset
5539 corresponding to the current ansi codepage */
5540 if (!csi
.fs
.fsCsb
[0])
5543 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5544 FIXME("TCI failed on codepage %d\n", acp
);
5545 csi
.fs
.fsCsb
[0] = 0;
5547 lf
.lfCharSet
= csi
.ciCharset
;
5550 want_vertical
= (lf
.lfFaceName
[0] == '@');
5552 /* Face families are in the top 4 bits of lfPitchAndFamily,
5553 so mask with 0xF0 before testing */
5555 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5556 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5557 strcpyW(lf
.lfFaceName
, defFixed
);
5558 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5559 strcpyW(lf
.lfFaceName
, defSerif
);
5560 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5561 strcpyW(lf
.lfFaceName
, defSans
);
5563 strcpyW(lf
.lfFaceName
, defSans
);
5564 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5565 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5566 font_link
= find_font_link(family
->FamilyName
);
5567 face_list
= get_face_list_from_family(family
);
5568 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5569 if (!(face
->scalable
|| can_use_bitmap
))
5571 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5573 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5579 last_resort_family
= NULL
;
5580 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5581 font_link
= find_font_link(family
->FamilyName
);
5582 face_list
= get_face_list_from_family(family
);
5583 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5584 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5585 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5586 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5589 if(can_use_bitmap
&& !last_resort_family
)
5590 last_resort_family
= family
;
5595 if(last_resort_family
) {
5596 family
= last_resort_family
;
5597 csi
.fs
.fsCsb
[0] = 0;
5601 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5602 face_list
= get_face_list_from_family(family
);
5603 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5604 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5605 csi
.fs
.fsCsb
[0] = 0;
5606 WARN("just using first face for now\n");
5609 if(can_use_bitmap
&& !last_resort_family
)
5610 last_resort_family
= family
;
5613 if(!last_resort_family
) {
5614 FIXME("can't find a single appropriate font - bailing\n");
5620 WARN("could only find a bitmap font - this will probably look awful!\n");
5621 family
= last_resort_family
;
5622 csi
.fs
.fsCsb
[0] = 0;
5625 it
= lf
.lfItalic
? 1 : 0;
5626 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5628 height
= lf
.lfHeight
;
5630 face
= best
= best_bitmap
= NULL
;
5631 font_link
= find_font_link(family
->FamilyName
);
5632 face_list
= get_face_list_from_family(family
);
5633 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5635 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5636 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5641 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5642 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5643 new_score
= (italic
^ it
) + (bold
^ bd
);
5644 if(!best
|| new_score
<= score
)
5646 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5647 italic
, bold
, it
, bd
);
5650 if(best
->scalable
&& score
== 0) break;
5654 newdiff
= height
- (signed int)(best
->size
.height
);
5656 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5657 if(!best_bitmap
|| new_score
< score
||
5658 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5660 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5663 if(score
== 0 && diff
== 0) break;
5670 face
= best
->scalable
? best
: best_bitmap
;
5671 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5672 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5675 height
= lf
.lfHeight
;
5679 if(csi
.fs
.fsCsb
[0]) {
5680 ret
->charset
= lf
.lfCharSet
;
5681 ret
->codepage
= csi
.ciACP
;
5684 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5686 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5687 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5689 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5691 if(!face
->scalable
) {
5692 /* Windows uses integer scaling factors for bitmap fonts */
5693 INT scale
, scaled_height
;
5694 GdiFont
*cachedfont
;
5696 /* FIXME: rotation of bitmap fonts is ignored */
5697 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5699 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5700 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5701 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5702 /* As we changed the matrix, we need to search the cache for the font again,
5703 * otherwise we might explode the cache. */
5704 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5705 TRACE("Found cached font after non-scalable matrix rescale!\n");
5710 calc_hash(&ret
->font_desc
);
5712 if (height
!= 0) height
= diff
;
5713 height
+= face
->size
.height
;
5715 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5716 scaled_height
= scale
* face
->size
.height
;
5717 /* Only jump to the next height if the difference <= 25% original height */
5718 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5719 /* The jump between unscaled and doubled is delayed by 1 */
5720 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5721 ret
->scale_y
= scale
;
5723 width
= face
->size
.x_ppem
>> 6;
5724 height
= face
->size
.y_ppem
>> 6;
5728 TRACE("font scale y: %f\n", ret
->scale_y
);
5730 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5739 fill_fileinfo_from_face( ret
, face
);
5740 ret
->ntmFlags
= face
->ntmFlags
;
5742 pick_charmap( ret
->ft_face
, ret
->charset
);
5744 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5745 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5746 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5747 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5748 create_child_font_list(ret
);
5750 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5752 int length
= get_font_data(ret
, MS_GSUB_TAG
, 0, NULL
, 0);
5753 if (length
!= GDI_ERROR
)
5755 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5756 get_font_data(ret
, MS_GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5757 TRACE("Loaded GSUB table of %i bytes\n",length
);
5758 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5759 if (!ret
->vert_feature
)
5761 TRACE("Vertical feature not found\n");
5762 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5763 ret
->GSUB_Table
= NULL
;
5767 ret
->aa_flags
= HIWORD( face
->flags
);
5769 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5775 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5777 switch (lf
.lfQuality
)
5779 case NONANTIALIASED_QUALITY
:
5780 case ANTIALIASED_QUALITY
:
5781 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5783 case CLEARTYPE_QUALITY
:
5784 case CLEARTYPE_NATURAL_QUALITY
:
5786 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5787 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5789 /* fixup the antialiasing flags for that font */
5792 case WINE_GGO_HRGB_BITMAP
:
5793 case WINE_GGO_HBGR_BITMAP
:
5794 case WINE_GGO_VRGB_BITMAP
:
5795 case WINE_GGO_VBGR_BITMAP
:
5796 if (is_subpixel_rendering_enabled()) break;
5797 *aa_flags
= GGO_GRAY4_BITMAP
;
5799 case GGO_GRAY2_BITMAP
:
5800 case GGO_GRAY4_BITMAP
:
5801 case GGO_GRAY8_BITMAP
:
5802 case WINE_GGO_GRAY16_BITMAP
:
5803 if ((!antialias_fakes
|| (!ret
->fake_bold
&& !ret
->fake_italic
)) && is_hinting_enabled())
5806 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5808 TRACE( "font %s %d aa disabled by GASP\n",
5809 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5810 *aa_flags
= GGO_BITMAP
;
5815 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5816 release_font( physdev
->font
);
5817 physdev
->font
= ret
;
5819 LeaveCriticalSection( &freetype_cs
);
5820 return ret
? hfont
: 0;
5823 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5830 id
+= IDS_FIRST_SCRIPT
;
5831 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5832 if (!rsrc
) return 0;
5833 hMem
= LoadResource( gdi32_module
, rsrc
);
5834 if (!hMem
) return 0;
5836 p
= LockResource( hMem
);
5838 while (id
--) p
+= *p
+ 1;
5840 i
= min(LF_FACESIZE
- 1, *p
);
5841 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5846 static inline BOOL
is_complex_script_ansi_cp(UINT ansi_cp
)
5848 return (ansi_cp
== 874 /* Thai */
5849 || ansi_cp
== 1255 /* Hebrew */
5850 || ansi_cp
== 1256 /* Arabic */
5854 /***************************************************
5855 * create_enum_charset_list
5857 * This function creates charset enumeration list because in DEFAULT_CHARSET
5858 * case, the ANSI codepage's charset takes precedence over other charsets.
5859 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5860 * This function works as a filter other than DEFAULT_CHARSET case.
5862 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5867 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5868 csi
.fs
.fsCsb
[0] != 0) {
5869 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5870 list
->element
[n
].charset
= csi
.ciCharset
;
5871 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5874 else { /* charset is DEFAULT_CHARSET or invalid. */
5878 /* Set the current codepage's charset as the first element. */
5880 if (!is_complex_script_ansi_cp(acp
) &&
5881 TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5882 csi
.fs
.fsCsb
[0] != 0) {
5883 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5884 list
->element
[n
].charset
= csi
.ciCharset
;
5885 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5886 mask
|= csi
.fs
.fsCsb
[0];
5890 /* Fill out left elements. */
5891 for (i
= 0; i
< 32; i
++) {
5893 fs
.fsCsb
[0] = 1L << i
;
5895 if (fs
.fsCsb
[0] & mask
)
5896 continue; /* skip, already added. */
5897 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5898 continue; /* skip, this is an invalid fsCsb bit. */
5900 list
->element
[n
].mask
= fs
.fsCsb
[0];
5901 list
->element
[n
].charset
= csi
.ciCharset
;
5902 load_script_name( i
, list
->element
[n
].name
);
5903 mask
|= fs
.fsCsb
[0];
5907 /* add catch all mask for remaining bits */
5910 list
->element
[n
].mask
= ~mask
;
5911 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5912 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5921 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5922 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5927 if (face
->cached_enum_data
)
5930 *pelf
= face
->cached_enum_data
->elf
;
5931 *pntm
= face
->cached_enum_data
->ntm
;
5932 *ptype
= face
->cached_enum_data
->type
;
5936 font
= alloc_font();
5938 if(face
->scalable
) {
5942 height
= face
->size
.y_ppem
>> 6;
5943 width
= face
->size
.x_ppem
>> 6;
5945 font
->scale_y
= 1.0;
5947 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5953 font
->name
= strdupW( family_name
);
5954 font
->ntmFlags
= face
->ntmFlags
;
5956 if (get_outline_text_metrics(font
))
5958 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5960 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5961 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5962 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5964 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5965 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5967 lstrcpynW(pelf
->elfFullName
,
5968 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5970 lstrcpynW(pelf
->elfStyle
,
5971 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5976 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5978 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5979 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5980 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5982 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5984 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5986 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5987 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5990 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5991 pntm
->ntmFontSig
= face
->fs
;
5993 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5995 pelf
->elfLogFont
.lfEscapement
= 0;
5996 pelf
->elfLogFont
.lfOrientation
= 0;
5997 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5998 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5999 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
6000 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
6001 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
6002 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
6003 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
6004 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
6005 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
6006 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
6007 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
6010 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
6011 *ptype
|= TRUETYPE_FONTTYPE
;
6012 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
6013 *ptype
|= DEVICE_FONTTYPE
;
6014 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
6015 *ptype
|= RASTER_FONTTYPE
;
6017 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
6018 if (face
->cached_enum_data
)
6020 face
->cached_enum_data
->elf
= *pelf
;
6021 face
->cached_enum_data
->ntm
= *pntm
;
6022 face
->cached_enum_data
->type
= *ptype
;
6028 static BOOL
family_matches(Family
*family
, const WCHAR
*face_name
)
6031 const struct list
*face_list
;
6033 if (!strcmpiW(face_name
, family
->FamilyName
)) return TRUE
;
6035 face_list
= get_face_list_from_family(family
);
6036 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
6037 if (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
)) return TRUE
;
6042 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const WCHAR
*face_name
)
6044 if (!strcmpiW(face_name
, family_name
)) return TRUE
;
6046 return (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
));
6049 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
6050 FONTENUMPROCW proc
, LPARAM lparam
, const WCHAR
*subst
)
6053 NEWTEXTMETRICEXW ntm
;
6057 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
6058 for(i
= 0; i
< list
->total
; i
++) {
6059 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
6060 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
6061 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
6062 i
= list
->total
; /* break out of loop after enumeration */
6066 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
6067 /* use the DEFAULT_CHARSET case only if no other charset is present */
6068 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
6069 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
6070 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
6071 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
6072 if (!elf
.elfScript
[0])
6073 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
6075 /* Font Replacement */
6076 if (family
!= face
->family
)
6078 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
6080 strcpyW(elf
.elfFullName
, face
->FullName
);
6082 strcpyW(elf
.elfFullName
, family
->FamilyName
);
6085 strcpyW(elf
.elfLogFont
.lfFaceName
, subst
);
6086 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
6087 debugstr_w(elf
.elfLogFont
.lfFaceName
),
6088 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
6089 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
6090 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
6091 ntm
.ntmTm
.ntmFlags
);
6092 /* release section before callback (FIXME) */
6093 LeaveCriticalSection( &freetype_cs
);
6094 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
6095 EnterCriticalSection( &freetype_cs
);
6100 /*************************************************************
6101 * freetype_EnumFonts
6103 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
6107 const struct list
*face_list
;
6109 struct enum_charset_list enum_charsets
;
6113 lf
.lfCharSet
= DEFAULT_CHARSET
;
6114 lf
.lfPitchAndFamily
= 0;
6115 lf
.lfFaceName
[0] = 0;
6119 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
6121 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
6124 EnterCriticalSection( &freetype_cs
);
6125 if(plf
->lfFaceName
[0]) {
6126 WCHAR
*face_name
= plf
->lfFaceName
;
6127 FontSubst
*psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
6130 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
6131 debugstr_w(psub
->to
.name
));
6132 face_name
= psub
->to
.name
;
6135 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
6136 if (!family_matches(family
, face_name
)) continue;
6137 face_list
= get_face_list_from_family(family
);
6138 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
6139 if (!face_matches(family
->FamilyName
, face
, face_name
)) continue;
6140 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, psub
? psub
->from
.name
: NULL
)) return FALSE
;
6144 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
6145 face_list
= get_face_list_from_family(family
);
6146 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
6147 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, NULL
)) return FALSE
;
6150 LeaveCriticalSection( &freetype_cs
);
6154 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
6156 pt
->x
.value
= vec
->x
>> 6;
6157 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
6158 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
6159 pt
->y
.value
= vec
->y
>> 6;
6160 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
6161 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
6164 /***************************************************
6165 * According to the MSDN documentation on WideCharToMultiByte,
6166 * certain codepages cannot set the default_used parameter.
6167 * This returns TRUE if the codepage can set that parameter, false else
6168 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
6170 static BOOL
codepage_sets_default_used(UINT codepage
)
6184 * GSUB Table handling functions
6187 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
6189 const GSUB_CoverageFormat1
* cf1
;
6193 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
6195 int count
= GET_BE_WORD(cf1
->GlyphCount
);
6197 TRACE("Coverage Format 1, %i glyphs\n",count
);
6198 for (i
= 0; i
< count
; i
++)
6199 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
6203 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
6205 const GSUB_CoverageFormat2
* cf2
;
6208 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
6210 count
= GET_BE_WORD(cf2
->RangeCount
);
6211 TRACE("Coverage Format 2, %i ranges\n",count
);
6212 for (i
= 0; i
< count
; i
++)
6214 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
6216 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
6217 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
6219 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
6220 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
6226 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
6231 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
6235 const GSUB_LookupList
*lookup
;
6236 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
6238 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
6239 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
6241 const GSUB_LookupTable
*look
;
6242 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
6243 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
6244 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
6245 if (GET_BE_WORD(look
->LookupType
) != 1)
6246 FIXME("We only handle SubType 1\n");
6251 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
6253 const GSUB_SingleSubstFormat1
*ssf1
;
6254 offset
= GET_BE_WORD(look
->SubTable
[j
]);
6255 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
6256 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
6258 int offset
= GET_BE_WORD(ssf1
->Coverage
);
6259 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
6260 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
6262 TRACE(" Glyph 0x%x ->",glyph
);
6263 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
6264 TRACE(" 0x%x\n",glyph
);
6269 const GSUB_SingleSubstFormat2
*ssf2
;
6273 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
6274 offset
= GET_BE_WORD(ssf1
->Coverage
);
6275 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
6276 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
6277 TRACE(" Coverage index %i\n",index
);
6280 TRACE(" Glyph is 0x%x ->",glyph
);
6281 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
6282 TRACE("0x%x\n",glyph
);
6292 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
6294 const GSUB_Header
*header
;
6295 const GSUB_Feature
*feature
;
6297 if (!font
->GSUB_Table
)
6300 header
= font
->GSUB_Table
;
6301 feature
= font
->vert_feature
;
6303 return GSUB_apply_feature(header
, feature
, glyph
);
6306 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
6310 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6311 WCHAR wc
= (WCHAR
)glyph
;
6313 BOOL
*default_used_pointer
;
6316 default_used_pointer
= NULL
;
6317 default_used
= FALSE
;
6318 if (codepage_sets_default_used(font
->codepage
))
6319 default_used_pointer
= &default_used
;
6320 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6322 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6323 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6328 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6329 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6333 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6335 if (glyph
< 0x100) glyph
+= 0xf000;
6336 /* there is a number of old pre-Unicode "broken" TTFs, which
6337 do have symbols at U+00XX instead of U+f0XX */
6338 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6339 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6341 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6346 /* helper for freetype_GetGlyphIndices */
6347 static FT_UInt
get_gdi_glyph_index(const GdiFont
*font
, UINT glyph
)
6349 WCHAR wc
= (WCHAR
)glyph
;
6350 BOOL default_used
= FALSE
;
6351 BOOL
*default_used_pointer
= NULL
;
6355 if(font
->ft_face
->charmap
->encoding
!= FT_ENCODING_NONE
)
6356 return get_glyph_index(font
, glyph
);
6358 if (codepage_sets_default_used(font
->codepage
))
6359 default_used_pointer
= &default_used
;
6360 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
)
6363 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6364 ret
= (unsigned char)wc
;
6369 ret
= (unsigned char)buf
;
6370 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6374 static FT_UInt
get_default_char_index(GdiFont
*font
)
6376 FT_UInt default_char
;
6378 if (FT_IS_SFNT(font
->ft_face
))
6380 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6381 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6386 get_text_metrics(font
, &textm
);
6387 default_char
= textm
.tmDefaultChar
;
6390 return default_char
;
6393 /*************************************************************
6394 * freetype_GetGlyphIndices
6396 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6398 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6401 BOOL got_default
= FALSE
;
6405 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6406 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6409 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6411 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6416 EnterCriticalSection( &freetype_cs
);
6418 for(i
= 0; i
< count
; i
++)
6420 pgi
[i
] = get_gdi_glyph_index(physdev
->font
, lpstr
[i
]);
6425 default_char
= get_default_char_index(physdev
->font
);
6428 pgi
[i
] = default_char
;
6431 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6433 LeaveCriticalSection( &freetype_cs
);
6437 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6439 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6440 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6443 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6445 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6446 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6449 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
6453 len
= pFT_Vector_Length(vec
);
6455 out
.x
= (vec
->x
<< 6) / len
;
6456 out
.y
= (vec
->y
<< 6) / len
;
6463 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
6469 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
6471 if(!pFT_Outline_Embolden
)
6474 strength
= MulDiv(ppem
, 1 << 6, 24);
6475 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
6477 TRACE("FT_Ouline_Embolden returns %d\n", err
);
6481 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
6482 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
6483 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
6484 metrics
->horiBearingX
= bbox
.xMin
;
6485 metrics
->horiBearingY
= bbox
.yMax
;
6486 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
6487 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
6491 static inline BYTE
get_max_level( UINT format
)
6495 case GGO_GRAY2_BITMAP
: return 4;
6496 case GGO_GRAY4_BITMAP
: return 16;
6497 case GGO_GRAY8_BITMAP
: return 64;
6502 extern const unsigned short vertical_orientation_table
[] DECLSPEC_HIDDEN
;
6504 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6506 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[uchar
>> 8]+((uchar
>> 4) & 0x0f)]+ (uchar
& 0xf)];
6508 /* We only reach this code if typographical substitution did not occur */
6509 /* Type: U or Type: Tu */
6510 return (orientation
== 1 || orientation
== 3);
6513 static FT_Vector
get_advance_metric(GdiFont
*incoming_font
, GdiFont
*font
,
6514 const FT_Glyph_Metrics
*metrics
,
6515 const FT_Matrix
*transMat
, BOOL vertical_metrics
)
6518 FT_Fixed base_advance
, em_scale
= 0;
6519 BOOL fixed_pitch_full
= FALSE
;
6521 if (vertical_metrics
)
6522 base_advance
= metrics
->vertAdvance
;
6524 base_advance
= metrics
->horiAdvance
;
6526 adv
.x
= base_advance
;
6529 /* In fixed-pitch font, we adjust the fullwidth character advance so that
6530 they have double halfwidth character width. E.g. if the font is 19 ppem,
6531 we return 20 (not 19) for fullwidth characters as we return 10 for
6532 halfwidth characters. */
6533 if(FT_IS_SCALABLE(incoming_font
->ft_face
) &&
6534 (incoming_font
->potm
|| get_outline_text_metrics(incoming_font
)) &&
6535 !(incoming_font
->potm
->otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6537 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16,
6538 incoming_font
->ft_face
->units_per_EM
);
6539 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6540 fixed_pitch_full
= (avg_advance
> 0 &&
6541 (base_advance
+ 63) >> 6 ==
6542 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
6543 if (fixed_pitch_full
&& !transMat
)
6544 adv
.x
= (avg_advance
* 2) << 6;
6548 pFT_Vector_Transform(&adv
, transMat
);
6549 if (fixed_pitch_full
&& adv
.y
== 0) {
6551 vec
.x
= incoming_font
->ntmAvgWidth
;
6553 pFT_Vector_Transform(&vec
, transMat
);
6554 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
6558 if (font
->fake_bold
) {
6562 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
6563 pFT_Vector_Transform(&vec
, transMat
);
6564 fake_bold_adv
= normalize_vector(&vec
);
6565 adv
.x
+= fake_bold_adv
.x
;
6566 adv
.y
+= fake_bold_adv
.y
;
6570 adv
.x
= (adv
.x
+ 63) & -64;
6571 adv
.y
= -((adv
.y
+ 63) & -64);
6575 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6577 TTPOLYGONHEADER
*pph
;
6579 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
6580 unsigned int pph_start
, cpfx
;
6583 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6585 /* Ignore contours containing one point */
6586 if (point
== outline
->contours
[contour
])
6593 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6597 pph
->dwType
= TT_POLYGON_TYPE
;
6598 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6600 needed
+= sizeof(*pph
);
6602 while (point
<= outline
->contours
[contour
])
6604 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6605 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6606 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6611 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6614 } while (point
<= outline
->contours
[contour
] &&
6615 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6616 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6617 /* At the end of a contour Windows adds the start point, but
6619 if (point
> outline
->contours
[contour
] &&
6620 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6623 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6626 else if (point
<= outline
->contours
[contour
] &&
6627 outline
->tags
[point
] & FT_Curve_Tag_On
)
6629 /* add closing pt for bezier */
6631 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6640 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6643 pph
->cb
= needed
- pph_start
;
6648 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6650 /* Convert the quadratic Beziers to cubic Beziers.
6651 The parametric eqn for a cubic Bezier is, from PLRM:
6652 r(t) = at^3 + bt^2 + ct + r0
6653 with the control points:
6658 A quadratic Bezier has the form:
6659 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6661 So equating powers of t leads to:
6662 r1 = 2/3 p1 + 1/3 p0
6663 r2 = 2/3 p1 + 1/3 p2
6664 and of course r0 = p0, r3 = p2
6666 int contour
, point
= 0, first_pt
;
6667 TTPOLYGONHEADER
*pph
;
6669 DWORD pph_start
, cpfx
, type
;
6670 FT_Vector cubic_control
[4];
6671 unsigned int needed
= 0;
6673 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6676 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6680 pph
->dwType
= TT_POLYGON_TYPE
;
6681 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6683 needed
+= sizeof(*pph
);
6685 while (point
<= outline
->contours
[contour
])
6687 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6688 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6689 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6693 if (type
== TT_PRIM_LINE
)
6696 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6702 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6705 /* FIXME: Possible optimization in endpoint calculation
6706 if there are two consecutive curves */
6707 cubic_control
[0] = outline
->points
[point
-1];
6708 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6710 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6711 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6712 cubic_control
[0].x
>>= 1;
6713 cubic_control
[0].y
>>= 1;
6715 if (point
+1 > outline
->contours
[contour
])
6716 cubic_control
[3] = outline
->points
[first_pt
];
6719 cubic_control
[3] = outline
->points
[point
+1];
6720 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
6722 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6723 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6724 cubic_control
[3].x
>>= 1;
6725 cubic_control
[3].y
>>= 1;
6728 /* r1 = 1/3 p0 + 2/3 p1
6729 r2 = 1/3 p2 + 2/3 p1 */
6730 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6731 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6732 cubic_control
[2] = cubic_control
[1];
6733 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6734 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6735 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6736 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6739 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6740 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6741 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6746 } while (point
<= outline
->contours
[contour
] &&
6747 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6748 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6749 /* At the end of a contour Windows adds the start point,
6750 but only for Beziers and we've already done that.
6752 if (point
<= outline
->contours
[contour
] &&
6753 outline
->tags
[point
] & FT_Curve_Tag_On
)
6755 /* This is the closing pt of a bezier, but we've already
6756 added it, so just inc point and carry on */
6764 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6767 pph
->cb
= needed
- pph_start
;
6772 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6774 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6775 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6778 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6780 FT_Face ft_face
= incoming_font
->ft_face
;
6781 GdiFont
*font
= incoming_font
;
6782 FT_Glyph_Metrics metrics
;
6783 FT_UInt glyph_index
;
6784 DWORD width
, height
, pitch
, needed
= 0;
6785 FT_Bitmap ft_bitmap
;
6787 INT left
, right
, top
= 0, bottom
= 0;
6789 INT origin_x
= 0, origin_y
= 0;
6791 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6792 double widthRatio
= 1.0;
6793 FT_Matrix transMat
= identityMat
;
6794 FT_Matrix transMatUnrotated
;
6795 FT_Matrix transMatTategaki
;
6796 BOOL needsTransform
= FALSE
;
6797 BOOL tategaki
= (font
->name
[0] == '@');
6798 BOOL vertical_metrics
;
6799 UINT original_index
;
6801 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6802 buflen
, buf
, lpmat
);
6804 TRACE("font transform %f %f %f %f\n",
6805 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6806 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6808 if(format
& GGO_GLYPH_INDEX
) {
6809 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6810 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6811 as glyph index. "Treasure Adventure Game" depends on this. */
6812 glyph_index
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6813 TRACE("translate glyph index %04x -> %04x\n", glyph
, glyph_index
);
6815 glyph_index
= glyph
;
6816 original_index
= glyph_index
;
6817 format
&= ~GGO_GLYPH_INDEX
;
6818 /* TODO: Window also turns off tategaki for glyphs passed in by index
6819 if their unicode code points fall outside of the range that is
6823 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6824 ft_face
= font
->ft_face
;
6825 original_index
= glyph_index
;
6826 if (!vert
&& tategaki
)
6827 tategaki
= check_unicode_tategaki(glyph
);
6830 if(format
& GGO_UNHINTED
) {
6831 load_flags
|= FT_LOAD_NO_HINTING
;
6832 format
&= ~GGO_UNHINTED
;
6835 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6836 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6837 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6838 font
->gmsize
* sizeof(GM
*));
6840 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6841 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6843 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6844 *abc
= FONT_GM(font
,original_index
)->abc
;
6845 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6846 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6847 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6848 return 1; /* FIXME */
6852 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6853 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6855 /* Scaling factor */
6860 get_text_metrics(font
, &tm
);
6862 widthRatio
= (double)font
->aveWidth
;
6863 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6866 widthRatio
= font
->scale_y
;
6868 /* Scaling transform */
6869 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6872 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6875 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6877 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6878 needsTransform
= TRUE
;
6881 /* Slant transform */
6882 if (font
->fake_italic
) {
6885 slantMat
.xx
= (1 << 16);
6886 slantMat
.xy
= ((1 << 16) >> 2);
6888 slantMat
.yy
= (1 << 16);
6889 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6890 needsTransform
= TRUE
;
6893 /* Rotation transform */
6894 transMatUnrotated
= transMat
;
6895 transMatTategaki
= transMat
;
6896 if(font
->orientation
|| tategaki
) {
6897 FT_Matrix rotationMat
;
6898 FT_Matrix taterotationMat
;
6901 double orient
= font
->orientation
/ 10.0;
6902 double tate_orient
= 0.f
;
6905 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6907 tate_orient
= font
->orientation
/10.0;
6911 angle
= FT_FixedFromFloat(orient
);
6912 pFT_Vector_Unit(&vecAngle
, angle
);
6913 rotationMat
.xx
= vecAngle
.x
;
6914 rotationMat
.xy
= -vecAngle
.y
;
6915 rotationMat
.yx
= -rotationMat
.xy
;
6916 rotationMat
.yy
= rotationMat
.xx
;
6918 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6923 angle
= FT_FixedFromFloat(tate_orient
);
6924 pFT_Vector_Unit(&vecAngle
, angle
);
6925 taterotationMat
.xx
= vecAngle
.x
;
6926 taterotationMat
.xy
= -vecAngle
.y
;
6927 taterotationMat
.yx
= -taterotationMat
.xy
;
6928 taterotationMat
.yy
= taterotationMat
.xx
;
6929 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6932 needsTransform
= TRUE
;
6935 /* World transform */
6936 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6939 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6940 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6941 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6942 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6943 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6944 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6945 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6946 needsTransform
= TRUE
;
6949 /* Extra transformation specified by caller */
6950 if (!is_identity_MAT2(lpmat
))
6953 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6954 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6955 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6956 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6957 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6958 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6959 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6960 needsTransform
= TRUE
;
6963 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6964 /* there is a freetype bug where vertical metrics are only
6965 properly scaled and correct in 2.4.0 or greater */
6966 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6967 vertical_metrics
= FALSE
;
6969 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6970 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6972 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6975 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6979 metrics
= ft_face
->glyph
->metrics
;
6980 if(font
->fake_bold
) {
6981 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
6982 metrics
.width
+= 1 << 6;
6985 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6986 * by the text metrics. The proper behavior is to clip the glyph metrics to
6987 * fit within the maximums specified in the text metrics. */
6988 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6989 get_bitmap_text_metrics(incoming_font
)) {
6990 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6991 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6992 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6993 metrics
.horiBearingY
= top
;
6994 metrics
.height
= top
- bottom
;
6996 /* TODO: Are we supposed to clip the width as well...? */
6997 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
7000 if(!needsTransform
) {
7001 left
= (INT
)(metrics
.horiBearingX
) & -64;
7002 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
7003 top
= (metrics
.horiBearingY
+ 63) & -64;
7004 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
7005 adv
= get_advance_metric(incoming_font
, font
, &metrics
, NULL
, vertical_metrics
);
7006 gm
.gmCellIncX
= adv
.x
>> 6;
7010 abc
->abcA
= origin_x
>> 6;
7011 abc
->abcB
= metrics
.width
>> 6;
7019 for(xc
= 0; xc
< 2; xc
++) {
7020 for(yc
= 0; yc
< 2; yc
++) {
7021 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
7022 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
7023 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
7024 pFT_Vector_Transform(&vec
, &transMatTategaki
);
7025 if(xc
== 0 && yc
== 0) {
7026 left
= right
= vec
.x
;
7027 top
= bottom
= vec
.y
;
7029 if(vec
.x
< left
) left
= vec
.x
;
7030 else if(vec
.x
> right
) right
= vec
.x
;
7031 if(vec
.y
< bottom
) bottom
= vec
.y
;
7032 else if(vec
.y
> top
) top
= vec
.y
;
7037 right
= (right
+ 63) & -64;
7038 bottom
= bottom
& -64;
7039 top
= (top
+ 63) & -64;
7041 if (tategaki
&& (font
->potm
|| get_outline_text_metrics(font
)))
7043 if (vertical_metrics
)
7044 lsb
= metrics
.horiBearingY
+ metrics
.vertBearingY
;
7046 lsb
= metrics
.vertAdvance
+ (font
->potm
->otmDescent
<< 6);
7048 vec
.y
= font
->potm
->otmDescent
<< 6;
7049 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
7050 pFT_Vector_Transform(&vec
, &transMat
);
7051 origin_x
= (vec
.x
+ left
) & -64;
7052 origin_y
= (vec
.y
+ top
+ 63) & -64;
7058 lsb
= metrics
.horiBearingX
;
7061 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
7062 adv
= get_advance_metric(incoming_font
, font
, &metrics
, &transMat
, vertical_metrics
);
7063 gm
.gmCellIncX
= adv
.x
>> 6;
7064 gm
.gmCellIncY
= adv
.y
>> 6;
7066 adv
= get_advance_metric(incoming_font
, font
, &metrics
, &transMatUnrotated
, vertical_metrics
);
7070 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
7071 abc
->abcA
= vec
.x
>> 6;
7073 vec
.x
= metrics
.width
;
7075 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
7077 abc
->abcB
= vec
.x
>> 6;
7079 abc
->abcB
= -vec
.x
>> 6;
7082 width
= (right
- left
) >> 6;
7083 height
= (top
- bottom
) >> 6;
7084 gm
.gmBlackBoxX
= width
? width
: 1;
7085 gm
.gmBlackBoxY
= height
? height
: 1;
7086 gm
.gmptGlyphOrigin
.x
= origin_x
>> 6;
7087 gm
.gmptGlyphOrigin
.y
= origin_y
>> 6;
7088 if (!abc
->abcB
) abc
->abcB
= 1;
7089 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
7091 TRACE("%u,%u,%s,%d,%d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
7092 wine_dbgstr_point(&gm
.gmptGlyphOrigin
),
7093 gm
.gmCellIncX
, gm
.gmCellIncY
);
7095 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
7096 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
7098 FONT_GM(font
,original_index
)->gm
= gm
;
7099 FONT_GM(font
,original_index
)->abc
= *abc
;
7100 FONT_GM(font
,original_index
)->init
= TRUE
;
7103 if(format
== GGO_METRICS
)
7106 return 1; /* FIXME */
7109 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
7110 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
7112 TRACE("loaded a bitmap\n");
7118 pitch
= ((width
+ 31) >> 5) << 2;
7119 needed
= pitch
* height
;
7121 if(!buf
|| !buflen
) break;
7122 if (!needed
) return GDI_ERROR
; /* empty glyph */
7123 if (needed
> buflen
)
7126 switch(ft_face
->glyph
->format
) {
7127 case ft_glyph_format_bitmap
:
7129 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
7130 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
7131 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7133 if (!font
->fake_bold
)
7134 memcpy(dst
, src
, w
);
7138 for (x
= 0; x
< w
; x
++) {
7139 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
7141 dst
[x
+1] = (src
[x
] & 0x01) << 7;
7144 src
+= ft_face
->glyph
->bitmap
.pitch
;
7150 case ft_glyph_format_outline
:
7151 ft_bitmap
.width
= width
;
7152 ft_bitmap
.rows
= height
;
7153 ft_bitmap
.pitch
= pitch
;
7154 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
7155 ft_bitmap
.buffer
= buf
;
7158 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
7160 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
7162 /* Note: FreeType will only set 'black' bits for us. */
7163 memset(buf
, 0, needed
);
7164 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
7168 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
7173 case GGO_GRAY2_BITMAP
:
7174 case GGO_GRAY4_BITMAP
:
7175 case GGO_GRAY8_BITMAP
:
7176 case WINE_GGO_GRAY16_BITMAP
:
7178 unsigned int max_level
, row
, col
;
7181 pitch
= (width
+ 3) / 4 * 4;
7182 needed
= pitch
* height
;
7184 if(!buf
|| !buflen
) break;
7185 if (!needed
) return GDI_ERROR
; /* empty glyph */
7186 if (needed
> buflen
)
7189 max_level
= get_max_level( format
);
7191 switch(ft_face
->glyph
->format
) {
7192 case ft_glyph_format_bitmap
:
7194 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
7195 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7197 memset( buf
, 0, needed
);
7199 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++) {
7200 if (src
[x
/ 8] & masks
[x
% 8]) {
7202 if (font
->fake_bold
&& x
+1 < pitch
) dst
[x
+1] = max_level
;
7205 src
+= ft_face
->glyph
->bitmap
.pitch
;
7210 case ft_glyph_format_outline
:
7212 ft_bitmap
.width
= width
;
7213 ft_bitmap
.rows
= height
;
7214 ft_bitmap
.pitch
= pitch
;
7215 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
7216 ft_bitmap
.buffer
= buf
;
7219 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
7221 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
7223 memset(ft_bitmap
.buffer
, 0, buflen
);
7225 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
7227 if (max_level
!= 255)
7229 for (row
= 0, start
= buf
; row
< height
; row
++)
7231 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
7232 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
7240 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
7246 case WINE_GGO_HRGB_BITMAP
:
7247 case WINE_GGO_HBGR_BITMAP
:
7248 case WINE_GGO_VRGB_BITMAP
:
7249 case WINE_GGO_VBGR_BITMAP
:
7250 #ifdef FT_LCD_FILTER_H
7252 switch (ft_face
->glyph
->format
)
7254 case FT_GLYPH_FORMAT_BITMAP
:
7260 needed
= pitch
* height
;
7262 if (!buf
|| !buflen
) break;
7263 if (!needed
) return GDI_ERROR
; /* empty glyph */
7264 if (needed
> buflen
)
7267 memset(buf
, 0, buflen
);
7269 src
= ft_face
->glyph
->bitmap
.buffer
;
7270 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7272 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
7275 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
7277 if ( src
[x
/ 8] & masks
[x
% 8] )
7279 ((unsigned int *)dst
)[x
] = ~0u;
7280 if (font
->fake_bold
&& x
+1 < width
) ((unsigned int *)dst
)[x
+1] = ~0u;
7290 case FT_GLYPH_FORMAT_OUTLINE
:
7294 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
7295 INT x_shift
, y_shift
;
7297 FT_Render_Mode render_mode
=
7298 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
7299 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
7301 if (!width
|| !height
)
7303 if (!buf
|| !buflen
) break;
7307 if ( render_mode
== FT_RENDER_MODE_LCD
)
7309 gm
.gmBlackBoxX
+= 2;
7310 gm
.gmptGlyphOrigin
.x
-= 1;
7315 gm
.gmBlackBoxY
+= 2;
7316 gm
.gmptGlyphOrigin
.y
+= 1;
7320 width
= gm
.gmBlackBoxX
;
7321 height
= gm
.gmBlackBoxY
;
7323 needed
= pitch
* height
;
7325 if (!buf
|| !buflen
) break;
7326 if (needed
> buflen
)
7329 memset(buf
, 0, buflen
);
7331 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
7333 if ( needsTransform
)
7334 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
7336 if ( pFT_Library_SetLcdFilter
)
7337 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
7338 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
7340 src
= ft_face
->glyph
->bitmap
.buffer
;
7341 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7342 src_width
= ft_face
->glyph
->bitmap
.width
;
7343 src_height
= ft_face
->glyph
->bitmap
.rows
;
7345 if ( render_mode
== FT_RENDER_MODE_LCD
)
7353 rgb_interval
= src_pitch
;
7358 x_shift
= ft_face
->glyph
->bitmap_left
- (left
>> 6);
7361 src
+= hmul
* -x_shift
;
7362 src_width
-= hmul
* -x_shift
;
7364 else if ( x_shift
> 0 )
7370 y_shift
= (top
>> 6) - ft_face
->glyph
->bitmap_top
;
7373 src
+= src_pitch
* vmul
* -y_shift
;
7374 src_height
-= vmul
* -y_shift
;
7376 else if ( y_shift
> 0 )
7378 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
7382 width
= min( width
, src_width
/ hmul
);
7383 height
= min( height
, src_height
/ vmul
);
7387 for ( x
= 0; x
< width
; x
++ )
7391 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
7392 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7393 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
7394 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7398 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
7399 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7400 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
7401 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7404 src
+= src_pitch
* vmul
;
7405 dst
+= pitch
/ sizeof(*dst
);
7412 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
7424 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7426 if(buflen
== 0) buf
= NULL
;
7428 if (needsTransform
&& buf
)
7429 pFT_Outline_Transform(outline
, &transMatTategaki
);
7431 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
7433 if (!buf
|| !buflen
)
7435 if (needed
> buflen
)
7438 get_native_glyph_outline(outline
, buflen
, buf
);
7443 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7444 if(buflen
== 0) buf
= NULL
;
7446 if (needsTransform
&& buf
)
7447 pFT_Outline_Transform(outline
, &transMat
);
7449 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
7451 if (!buf
|| !buflen
)
7453 if (needed
> buflen
)
7456 get_bezier_glyph_outline(outline
, buflen
, buf
);
7461 FIXME("Unsupported format %d\n", format
);
7468 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7470 FT_Face ft_face
= font
->ft_face
;
7471 FT_WinFNT_HeaderRec winfnt_header
;
7472 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7473 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7474 font
->potm
->otmSize
= size
;
7476 #define TM font->potm->otmTextMetrics
7477 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7479 TM
.tmHeight
= winfnt_header
.pixel_height
;
7480 TM
.tmAscent
= winfnt_header
.ascent
;
7481 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7482 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7483 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7484 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7485 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7486 TM
.tmWeight
= winfnt_header
.weight
;
7488 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7489 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7490 TM
.tmFirstChar
= winfnt_header
.first_char
;
7491 TM
.tmLastChar
= winfnt_header
.last_char
;
7492 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7493 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7494 TM
.tmItalic
= winfnt_header
.italic
;
7495 TM
.tmUnderlined
= font
->underline
;
7496 TM
.tmStruckOut
= font
->strikeout
;
7497 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7498 TM
.tmCharSet
= winfnt_header
.charset
;
7502 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7503 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7504 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7505 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7506 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7507 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7508 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7509 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7511 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7512 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7514 TM
.tmLastChar
= 255;
7515 TM
.tmDefaultChar
= 32;
7516 TM
.tmBreakChar
= 32;
7517 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7518 TM
.tmUnderlined
= font
->underline
;
7519 TM
.tmStruckOut
= font
->strikeout
;
7520 /* NB inverted meaning of TMPF_FIXED_PITCH */
7521 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
7522 TM
.tmCharSet
= font
->charset
;
7530 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7532 double scale_x
, scale_y
;
7536 scale_x
= (double)font
->aveWidth
;
7537 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7540 scale_x
= font
->scale_y
;
7542 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7543 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7545 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7546 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7548 SCALE_Y(ptm
->tmHeight
);
7549 SCALE_Y(ptm
->tmAscent
);
7550 SCALE_Y(ptm
->tmDescent
);
7551 SCALE_Y(ptm
->tmInternalLeading
);
7552 SCALE_Y(ptm
->tmExternalLeading
);
7553 SCALE_Y(ptm
->tmOverhang
);
7555 SCALE_X(ptm
->tmAveCharWidth
);
7556 SCALE_X(ptm
->tmMaxCharWidth
);
7562 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7564 double scale_x
, scale_y
;
7568 scale_x
= (double)font
->aveWidth
;
7569 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7572 scale_x
= font
->scale_y
;
7574 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7575 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7577 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7579 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7580 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7582 SCALE_Y(potm
->otmAscent
);
7583 SCALE_Y(potm
->otmDescent
);
7584 SCALE_Y(potm
->otmLineGap
);
7585 SCALE_Y(potm
->otmsCapEmHeight
);
7586 SCALE_Y(potm
->otmsXHeight
);
7587 SCALE_Y(potm
->otmrcFontBox
.top
);
7588 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7589 SCALE_X(potm
->otmrcFontBox
.left
);
7590 SCALE_X(potm
->otmrcFontBox
.right
);
7591 SCALE_Y(potm
->otmMacAscent
);
7592 SCALE_Y(potm
->otmMacDescent
);
7593 SCALE_Y(potm
->otmMacLineGap
);
7594 SCALE_X(potm
->otmptSubscriptSize
.x
);
7595 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7596 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7597 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7598 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7599 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7600 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7601 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7602 SCALE_Y(potm
->otmsStrikeoutSize
);
7603 SCALE_Y(potm
->otmsStrikeoutPosition
);
7604 SCALE_Y(potm
->otmsUnderscoreSize
);
7605 SCALE_Y(potm
->otmsUnderscorePosition
);
7611 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7615 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7617 /* Make sure that the font has sane width/height ratio */
7620 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7622 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7627 *ptm
= font
->potm
->otmTextMetrics
;
7628 scale_font_metrics(font
, ptm
);
7632 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7636 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7638 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7644 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7647 FT_Face ft_face
= font
->ft_face
;
7648 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7650 TT_HoriHeader
*pHori
;
7651 TT_Postscript
*pPost
;
7653 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7655 INT ascent
, descent
;
7658 TRACE("font=%p\n", font
);
7660 if(!FT_IS_SCALABLE(ft_face
))
7663 needed
= sizeof(*font
->potm
);
7665 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7666 family_nameW
= strdupW(font
->name
);
7668 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7671 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7672 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7674 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7676 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7679 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7680 face_nameW
= strdupW(font
->name
);
7682 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7683 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7685 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7688 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7689 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7690 full_nameW
= strdupW(fake_nameW
);
7692 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7694 /* These names should be read from the TT name table */
7696 /* length of otmpFamilyName */
7699 /* length of otmpFaceName */
7702 /* length of otmpStyleName */
7705 /* length of otmpFullName */
7709 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7711 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7713 FIXME("Can't find OS/2 table - not TT font?\n");
7717 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7719 FIXME("Can't find HHEA table - not TT font?\n");
7723 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7725 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",
7726 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7727 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7728 pOS2
->xAvgCharWidth
,
7729 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7730 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7731 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7733 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7734 font
->potm
->otmSize
= needed
;
7736 #define TM font->potm->otmTextMetrics
7738 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
7739 if(pOS2
->usWinAscent
+ windescent
== 0) {
7740 ascent
= pHori
->Ascender
;
7741 descent
= -pHori
->Descender
;
7743 ascent
= pOS2
->usWinAscent
;
7744 descent
= windescent
;
7747 font
->ntmCellHeight
= ascent
+ descent
;
7748 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7750 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7751 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7754 TM
.tmAscent
= font
->yMax
;
7755 TM
.tmDescent
= -font
->yMin
;
7756 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7758 TM
.tmAscent
= SCALE_Y(ascent
);
7759 TM
.tmDescent
= SCALE_Y(descent
);
7760 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7763 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7766 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7768 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7769 ((ascent
+ descent
) -
7770 (pHori
->Ascender
- pHori
->Descender
))));
7772 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7773 if (TM
.tmAveCharWidth
== 0) {
7774 TM
.tmAveCharWidth
= 1;
7776 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7777 TM
.tmWeight
= FW_REGULAR
;
7778 if (font
->fake_bold
) {
7779 TM
.tmAveCharWidth
++;
7780 TM
.tmMaxCharWidth
++;
7781 TM
.tmWeight
= FW_BOLD
;
7785 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7787 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7788 TM
.tmWeight
= pOS2
->usWeightClass
;
7790 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7791 TM
.tmWeight
= pOS2
->usWeightClass
;
7794 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7795 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7796 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7797 * symbol range to 0 - f0ff
7800 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7805 case 1255: /* Hebrew */
7806 TM
.tmLastChar
= 0xf896;
7808 case 1257: /* Baltic */
7809 TM
.tmLastChar
= 0xf8fd;
7812 TM
.tmLastChar
= 0xf0ff;
7814 TM
.tmBreakChar
= 0x20;
7815 TM
.tmDefaultChar
= 0x1f;
7819 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7820 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7822 if(pOS2
->usFirstCharIndex
<= 1)
7823 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7824 else if (pOS2
->usFirstCharIndex
> 0xff)
7825 TM
.tmBreakChar
= 0x20;
7827 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7828 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7830 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7831 TM
.tmUnderlined
= font
->underline
;
7832 TM
.tmStruckOut
= font
->strikeout
;
7834 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7835 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7836 (pOS2
->version
== 0xFFFFU
||
7837 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7838 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7840 TM
.tmPitchAndFamily
= 0;
7842 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7844 case PAN_FAMILY_SCRIPT
:
7845 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7848 case PAN_FAMILY_DECORATIVE
:
7849 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7854 case PAN_FAMILY_TEXT_DISPLAY
:
7855 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7856 /* which is clearly not what the panose spec says. */
7858 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7859 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7860 TM
.tmPitchAndFamily
= FF_MODERN
;
7863 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7868 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7871 case PAN_SERIF_COVE
:
7872 case PAN_SERIF_OBTUSE_COVE
:
7873 case PAN_SERIF_SQUARE_COVE
:
7874 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7875 case PAN_SERIF_SQUARE
:
7876 case PAN_SERIF_THIN
:
7877 case PAN_SERIF_BONE
:
7878 case PAN_SERIF_EXAGGERATED
:
7879 case PAN_SERIF_TRIANGLE
:
7880 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7883 case PAN_SERIF_NORMAL_SANS
:
7884 case PAN_SERIF_OBTUSE_SANS
:
7885 case PAN_SERIF_PERP_SANS
:
7886 case PAN_SERIF_FLARED
:
7887 case PAN_SERIF_ROUNDED
:
7888 TM
.tmPitchAndFamily
|= FF_SWISS
;
7895 if(FT_IS_SCALABLE(ft_face
))
7896 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7898 if(FT_IS_SFNT(ft_face
))
7900 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7901 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7903 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7906 TM
.tmCharSet
= font
->charset
;
7908 font
->potm
->otmFiller
= 0;
7909 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7910 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7911 if (font
->fake_italic
)
7912 font
->potm
->otmfsSelection
|= 1;
7913 if (font
->fake_bold
)
7914 font
->potm
->otmfsSelection
|= 1 << 5;
7915 /* Only return valid bits that define embedding and subsetting restrictions */
7916 font
->potm
->otmfsType
= pOS2
->fsType
& 0x30e;
7917 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7918 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7919 font
->potm
->otmItalicAngle
= 0; /* POST table */
7920 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7921 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7922 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7923 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7924 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7925 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7926 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7927 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7928 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7929 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7930 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7931 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7932 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7933 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7934 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7935 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7936 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7937 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7938 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7939 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7940 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7941 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7942 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7943 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7945 font
->potm
->otmsUnderscoreSize
= 0;
7946 font
->potm
->otmsUnderscorePosition
= 0;
7948 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7949 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7955 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7956 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7957 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7958 strcpyW((WCHAR
*)cp
, family_nameW
);
7960 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7961 strcpyW((WCHAR
*)cp
, style_nameW
);
7963 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7964 strcpyW((WCHAR
*)cp
, face_nameW
);
7966 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7967 strcpyW((WCHAR
*)cp
, full_nameW
);
7971 HeapFree(GetProcessHeap(), 0, style_nameW
);
7972 HeapFree(GetProcessHeap(), 0, family_nameW
);
7973 HeapFree(GetProcessHeap(), 0, face_nameW
);
7974 HeapFree(GetProcessHeap(), 0, full_nameW
);
7978 /*************************************************************
7979 * freetype_GetGlyphOutline
7981 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7982 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7984 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7990 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7991 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7995 EnterCriticalSection( &freetype_cs
);
7996 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7997 LeaveCriticalSection( &freetype_cs
);
8001 /*************************************************************
8002 * freetype_GetTextMetrics
8004 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
8006 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8011 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
8012 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
8016 EnterCriticalSection( &freetype_cs
);
8017 ret
= get_text_metrics( physdev
->font
, metrics
);
8018 LeaveCriticalSection( &freetype_cs
);
8022 /*************************************************************
8023 * freetype_GetOutlineTextMetrics
8025 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
8027 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8032 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
8033 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
8036 TRACE("font=%p\n", physdev
->font
);
8038 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
8041 EnterCriticalSection( &freetype_cs
);
8043 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
8045 if(potm
&& cbSize
>= physdev
->font
->potm
->otmSize
)
8047 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
8048 scale_outline_font_metrics(physdev
->font
, potm
);
8050 ret
= physdev
->font
->potm
->otmSize
;
8052 LeaveCriticalSection( &freetype_cs
);
8056 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
8058 child
->font
= alloc_font();
8059 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
8060 if(!child
->font
->ft_face
)
8062 free_font(child
->font
);
8067 child
->font
->font_desc
= font
->font_desc
;
8068 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
8069 child
->font
->orientation
= font
->orientation
;
8070 child
->font
->scale_y
= font
->scale_y
;
8071 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
8072 child
->font
->base_font
= font
;
8073 TRACE("created child font %p for base %p\n", child
->font
, font
);
8077 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
8080 CHILD_FONT
*child_font
;
8083 font
= font
->base_font
;
8085 *linked_font
= font
;
8087 if((*glyph
= get_glyph_index(font
, c
)))
8090 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
8091 *vert
= (o
!= *glyph
);
8095 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
8097 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
8099 if(!child_font
->font
)
8100 if(!load_child_font(font
, child_font
))
8103 if(!child_font
->font
->ft_face
)
8105 g
= get_glyph_index(child_font
->font
, c
);
8107 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
8111 *linked_font
= child_font
->font
;
8122 /*************************************************************
8123 * freetype_GetCharWidth
8125 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
8127 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8131 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8135 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
8136 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
8139 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
8142 EnterCriticalSection( &freetype_cs
);
8143 for(c
= firstChar
; c
<= lastChar
; c
++) {
8144 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
8145 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8147 LeaveCriticalSection( &freetype_cs
);
8151 /*************************************************************
8152 * freetype_GetCharABCWidths
8154 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
8156 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8159 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8163 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
8164 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
8167 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
8170 EnterCriticalSection( &freetype_cs
);
8172 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
8173 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
8175 LeaveCriticalSection( &freetype_cs
);
8179 /*************************************************************
8180 * freetype_GetCharABCWidthsI
8182 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
8184 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8187 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8191 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
8192 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
8195 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
8199 EnterCriticalSection( &freetype_cs
);
8201 for(c
= 0; c
< count
; c
++, buffer
++)
8202 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
8203 &gm
, buffer
, 0, NULL
, &identity
);
8205 LeaveCriticalSection( &freetype_cs
);
8209 /*************************************************************
8210 * freetype_GetTextExtentExPoint
8212 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
8214 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8218 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8222 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
8223 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
8226 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
8229 EnterCriticalSection( &freetype_cs
);
8231 for (idx
= pos
= 0; idx
< count
; idx
++)
8233 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
8234 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8238 LeaveCriticalSection( &freetype_cs
);
8242 /*************************************************************
8243 * freetype_GetTextExtentExPointI
8245 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
8247 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
8251 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8255 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
8256 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
8259 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
8262 EnterCriticalSection( &freetype_cs
);
8264 for (idx
= pos
= 0; idx
< count
; idx
++)
8266 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
8267 &gm
, &abc
, 0, NULL
, &identity
);
8268 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
8272 LeaveCriticalSection( &freetype_cs
);
8276 /*************************************************************
8277 * freetype_GetFontData
8279 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
8281 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8285 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
8286 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
8289 TRACE("font=%p, table=%s, offset=0x%x, buf=%p, cbData=0x%x\n",
8290 physdev
->font
, debugstr_an((char*)&table
, 4), offset
, buf
, cbData
);
8292 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
8295 /*************************************************************
8296 * freetype_GetTextFace
8298 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
8301 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8305 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
8306 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
8309 n
= strlenW(physdev
->font
->name
) + 1;
8312 lstrcpynW(str
, physdev
->font
->name
, count
);
8318 /*************************************************************
8319 * freetype_GetTextCharsetInfo
8321 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
8323 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8327 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
8328 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
8330 if (fs
) *fs
= physdev
->font
->fs
;
8331 return physdev
->font
->charset
;
8334 /* Retrieve a list of supported Unicode ranges for a given font.
8335 * Can be called with NULL gs to calculate the buffer size. Returns
8336 * the number of ranges found.
8338 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
8340 DWORD num_ranges
= 0;
8342 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8345 FT_ULong char_code
, char_code_prev
;
8348 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
8350 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8351 face
->num_glyphs
, glyph_code
, char_code
);
8353 if (!glyph_code
) return 0;
8357 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
8358 gs
->ranges
[0].cGlyphs
= 0;
8359 gs
->cGlyphsSupported
= 0;
8365 if (char_code
< char_code_prev
)
8367 ERR("expected increasing char code from FT_Get_Next_Char\n");
8370 if (char_code
- char_code_prev
> 1)
8375 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
8376 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
8377 gs
->cGlyphsSupported
++;
8382 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
8383 gs
->cGlyphsSupported
++;
8385 char_code_prev
= char_code
;
8386 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
8391 DWORD encoding
= RtlUlongByteSwap(face
->charmap
->encoding
);
8392 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
8398 /*************************************************************
8399 * freetype_GetFontUnicodeRanges
8401 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
8403 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8404 DWORD size
, num_ranges
;
8408 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
8409 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
8412 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
8413 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
8416 glyphset
->cbThis
= size
;
8417 glyphset
->cRanges
= num_ranges
;
8418 glyphset
->flAccel
= 0;
8423 /*************************************************************
8424 * freetype_FontIsLinked
8426 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
8428 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8433 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
8434 return dev
->funcs
->pFontIsLinked( dev
);
8438 EnterCriticalSection( &freetype_cs
);
8439 ret
= !list_empty(&physdev
->font
->child_fonts
);
8440 LeaveCriticalSection( &freetype_cs
);
8444 /*************************************************************************
8445 * GetRasterizerCaps (GDI32.@)
8447 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8449 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8450 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
8451 lprs
->nLanguageID
= 0;
8455 /*************************************************************
8456 * freetype_GetFontRealizationInfo
8458 static BOOL
freetype_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
8460 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8461 struct font_realization_info
*info
= ptr
;
8465 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
8466 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
8469 TRACE("(%p, %p)\n", physdev
->font
, info
);
8472 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8475 info
->cache_num
= physdev
->font
->cache_num
;
8476 info
->instance_id
= physdev
->font
->instance_id
;
8477 if (info
->size
== sizeof(*info
))
8480 info
->face_index
= physdev
->font
->ft_face
->face_index
;
8481 info
->simulations
= 0;
8482 if (physdev
->font
->fake_bold
)
8483 info
->simulations
|= 0x1;
8484 if (physdev
->font
->fake_italic
)
8485 info
->simulations
|= 0x2;
8491 /*************************************************************************
8492 * GetFontFileInfo (GDI32.@)
8494 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
, DWORD size
, DWORD
*needed
)
8496 struct font_handle_entry
*entry
= handle_entry( instance_id
);
8497 const GdiFont
*font
;
8501 SetLastError(ERROR_INVALID_PARAMETER
);
8506 *needed
= sizeof(*info
) + strlenW(font
->fileinfo
->path
) * sizeof(WCHAR
);
8509 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
8513 /* path is included too */
8514 memcpy(info
, font
->fileinfo
, *needed
);
8518 /*************************************************************************
8519 * Kerning support for TrueType fonts
8522 struct TT_kern_table
8528 struct TT_kern_subtable
8537 USHORT horizontal
: 1;
8539 USHORT cross_stream
: 1;
8540 USHORT override
: 1;
8541 USHORT reserved1
: 4;
8547 struct TT_format0_kern_subtable
8551 USHORT entrySelector
;
8562 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8563 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8564 const USHORT
*glyph_to_char
,
8565 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8568 const struct TT_kern_pair
*tt_kern_pair
;
8570 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8572 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8574 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8575 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8576 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8578 if (!kern_pair
|| !cPairs
)
8581 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8583 nPairs
= min(nPairs
, cPairs
);
8585 for (i
= 0; i
< nPairs
; i
++)
8587 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8588 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8589 /* this algorithm appears to better match what Windows does */
8590 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8591 if (kern_pair
->iKernAmount
< 0)
8593 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8594 kern_pair
->iKernAmount
-= font
->ppem
;
8596 else if (kern_pair
->iKernAmount
> 0)
8598 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8599 kern_pair
->iKernAmount
+= font
->ppem
;
8601 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8603 TRACE("left %u right %u value %d\n",
8604 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8608 TRACE("copied %u entries\n", nPairs
);
8612 /*************************************************************
8613 * freetype_GetKerningPairs
8615 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8619 const struct TT_kern_table
*tt_kern_table
;
8620 const struct TT_kern_subtable
*tt_kern_subtable
;
8622 USHORT
*glyph_to_char
;
8624 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8626 if (!(font
= physdev
->font
))
8628 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8629 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8633 EnterCriticalSection( &freetype_cs
);
8634 if (font
->total_kern_pairs
!= (DWORD
)-1)
8636 if (cPairs
&& kern_pair
)
8638 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8639 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8641 else cPairs
= font
->total_kern_pairs
;
8643 LeaveCriticalSection( &freetype_cs
);
8647 font
->total_kern_pairs
= 0;
8649 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8651 if (length
== GDI_ERROR
)
8653 TRACE("no kerning data in the font\n");
8654 LeaveCriticalSection( &freetype_cs
);
8658 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8661 WARN("Out of memory\n");
8662 LeaveCriticalSection( &freetype_cs
);
8666 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8668 /* build a glyph index to char code map */
8669 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8672 WARN("Out of memory allocating a glyph index to char code map\n");
8673 HeapFree(GetProcessHeap(), 0, buf
);
8674 LeaveCriticalSection( &freetype_cs
);
8678 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8684 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8686 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8687 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8691 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8693 /* FIXME: This doesn't match what Windows does: it does some fancy
8694 * things with duplicate glyph index to char code mappings, while
8695 * we just avoid overriding existing entries.
8697 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8698 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8700 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8705 DWORD encoding
= RtlUlongByteSwap(font
->ft_face
->charmap
->encoding
);
8708 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
8709 for (n
= 0; n
<= 65535; n
++)
8710 glyph_to_char
[n
] = (USHORT
)n
;
8713 tt_kern_table
= buf
;
8714 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8715 TRACE("version %u, nTables %u\n",
8716 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8718 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8720 for (i
= 0; i
< nTables
; i
++)
8722 struct TT_kern_subtable tt_kern_subtable_copy
;
8724 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8725 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8726 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8728 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8729 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8730 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8732 /* According to the TrueType specification this is the only format
8733 * that will be properly interpreted by Windows and OS/2
8735 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8737 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8739 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8740 glyph_to_char
, NULL
, 0);
8741 font
->total_kern_pairs
+= new_chunk
;
8743 if (!font
->kern_pairs
)
8744 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8745 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8747 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8748 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8750 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8751 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8754 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8756 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8759 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8760 HeapFree(GetProcessHeap(), 0, buf
);
8762 if (cPairs
&& kern_pair
)
8764 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8765 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8767 else cPairs
= font
->total_kern_pairs
;
8769 LeaveCriticalSection( &freetype_cs
);
8773 static const struct gdi_dc_funcs freetype_funcs
=
8775 NULL
, /* pAbortDoc */
8776 NULL
, /* pAbortPath */
8777 NULL
, /* pAlphaBlend */
8778 NULL
, /* pAngleArc */
8781 NULL
, /* pBeginPath */
8782 NULL
, /* pBlendImage */
8784 NULL
, /* pCloseFigure */
8785 NULL
, /* pCreateCompatibleDC */
8786 freetype_CreateDC
, /* pCreateDC */
8787 freetype_DeleteDC
, /* pDeleteDC */
8788 NULL
, /* pDeleteObject */
8789 NULL
, /* pDeviceCapabilities */
8790 NULL
, /* pEllipse */
8792 NULL
, /* pEndPage */
8793 NULL
, /* pEndPath */
8794 freetype_EnumFonts
, /* pEnumFonts */
8795 NULL
, /* pEnumICMProfiles */
8796 NULL
, /* pExcludeClipRect */
8797 NULL
, /* pExtDeviceMode */
8798 NULL
, /* pExtEscape */
8799 NULL
, /* pExtFloodFill */
8800 NULL
, /* pExtSelectClipRgn */
8801 NULL
, /* pExtTextOut */
8802 NULL
, /* pFillPath */
8803 NULL
, /* pFillRgn */
8804 NULL
, /* pFlattenPath */
8805 freetype_FontIsLinked
, /* pFontIsLinked */
8806 NULL
, /* pFrameRgn */
8807 NULL
, /* pGdiComment */
8808 NULL
, /* pGetBoundsRect */
8809 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8810 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8811 freetype_GetCharWidth
, /* pGetCharWidth */
8812 NULL
, /* pGetDeviceCaps */
8813 NULL
, /* pGetDeviceGammaRamp */
8814 freetype_GetFontData
, /* pGetFontData */
8815 freetype_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
8816 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8817 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8818 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8819 NULL
, /* pGetICMProfile */
8820 NULL
, /* pGetImage */
8821 freetype_GetKerningPairs
, /* pGetKerningPairs */
8822 NULL
, /* pGetNearestColor */
8823 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8824 NULL
, /* pGetPixel */
8825 NULL
, /* pGetSystemPaletteEntries */
8826 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8827 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8828 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8829 freetype_GetTextFace
, /* pGetTextFace */
8830 freetype_GetTextMetrics
, /* pGetTextMetrics */
8831 NULL
, /* pGradientFill */
8832 NULL
, /* pIntersectClipRect */
8833 NULL
, /* pInvertRgn */
8835 NULL
, /* pModifyWorldTransform */
8837 NULL
, /* pOffsetClipRgn */
8838 NULL
, /* pOffsetViewportOrg */
8839 NULL
, /* pOffsetWindowOrg */
8840 NULL
, /* pPaintRgn */
8843 NULL
, /* pPolyBezier */
8844 NULL
, /* pPolyBezierTo */
8845 NULL
, /* pPolyDraw */
8846 NULL
, /* pPolyPolygon */
8847 NULL
, /* pPolyPolyline */
8848 NULL
, /* pPolygon */
8849 NULL
, /* pPolyline */
8850 NULL
, /* pPolylineTo */
8851 NULL
, /* pPutImage */
8852 NULL
, /* pRealizeDefaultPalette */
8853 NULL
, /* pRealizePalette */
8854 NULL
, /* pRectangle */
8855 NULL
, /* pResetDC */
8856 NULL
, /* pRestoreDC */
8857 NULL
, /* pRoundRect */
8859 NULL
, /* pScaleViewportExt */
8860 NULL
, /* pScaleWindowExt */
8861 NULL
, /* pSelectBitmap */
8862 NULL
, /* pSelectBrush */
8863 NULL
, /* pSelectClipPath */
8864 freetype_SelectFont
, /* pSelectFont */
8865 NULL
, /* pSelectPalette */
8866 NULL
, /* pSelectPen */
8867 NULL
, /* pSetArcDirection */
8868 NULL
, /* pSetBkColor */
8869 NULL
, /* pSetBkMode */
8870 NULL
, /* pSetDCBrushColor */
8871 NULL
, /* pSetDCPenColor */
8872 NULL
, /* pSetDIBColorTable */
8873 NULL
, /* pSetDIBitsToDevice */
8874 NULL
, /* pSetDeviceClipping */
8875 NULL
, /* pSetDeviceGammaRamp */
8876 NULL
, /* pSetLayout */
8877 NULL
, /* pSetMapMode */
8878 NULL
, /* pSetMapperFlags */
8879 NULL
, /* pSetPixel */
8880 NULL
, /* pSetPolyFillMode */
8881 NULL
, /* pSetROP2 */
8882 NULL
, /* pSetRelAbs */
8883 NULL
, /* pSetStretchBltMode */
8884 NULL
, /* pSetTextAlign */
8885 NULL
, /* pSetTextCharacterExtra */
8886 NULL
, /* pSetTextColor */
8887 NULL
, /* pSetTextJustification */
8888 NULL
, /* pSetViewportExt */
8889 NULL
, /* pSetViewportOrg */
8890 NULL
, /* pSetWindowExt */
8891 NULL
, /* pSetWindowOrg */
8892 NULL
, /* pSetWorldTransform */
8893 NULL
, /* pStartDoc */
8894 NULL
, /* pStartPage */
8895 NULL
, /* pStretchBlt */
8896 NULL
, /* pStretchDIBits */
8897 NULL
, /* pStrokeAndFillPath */
8898 NULL
, /* pStrokePath */
8899 NULL
, /* pUnrealizePalette */
8900 NULL
, /* pWidenPath */
8901 NULL
, /* wine_get_wgl_driver */
8902 GDI_PRIORITY_FONT_DRV
/* priority */
8905 #else /* HAVE_FREETYPE */
8907 struct font_fileinfo
;
8909 /*************************************************************************/
8911 BOOL
WineEngInit(void)
8916 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8918 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8922 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8924 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8928 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8930 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8934 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8935 LPCWSTR font_file
, LPCWSTR font_path
)
8941 /*************************************************************************
8942 * GetRasterizerCaps (GDI32.@)
8944 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8946 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8948 lprs
->nLanguageID
= 0;
8952 /*************************************************************************
8953 * GetFontFileInfo (GDI32.@)
8955 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
, DWORD size
, DWORD
*needed
)
8961 #endif /* HAVE_FREETYPE */