2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font
);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType
;
144 static FT_Library library
= 0;
151 static FT_Version_t FT_Version
;
152 static DWORD FT_SimpleVersion
;
154 static void *ft_handle
= NULL
;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face
);
158 MAKE_FUNCPTR(FT_Get_Char_Index
);
159 MAKE_FUNCPTR(FT_Get_First_Char
);
160 MAKE_FUNCPTR(FT_Get_Module
);
161 MAKE_FUNCPTR(FT_Get_Next_Char
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
166 MAKE_FUNCPTR(FT_Init_FreeType
);
167 MAKE_FUNCPTR(FT_Library_Version
);
168 MAKE_FUNCPTR(FT_Load_Glyph
);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
170 MAKE_FUNCPTR(FT_Matrix_Multiply
);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix
);
176 MAKE_FUNCPTR(FT_New_Face
);
177 MAKE_FUNCPTR(FT_New_Memory_Face
);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
179 MAKE_FUNCPTR(FT_Outline_Transform
);
180 MAKE_FUNCPTR(FT_Outline_Translate
);
181 MAKE_FUNCPTR(FT_Render_Glyph
);
182 MAKE_FUNCPTR(FT_Select_Charmap
);
183 MAKE_FUNCPTR(FT_Set_Charmap
);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
185 MAKE_FUNCPTR(FT_Vector_Transform
);
186 MAKE_FUNCPTR(FT_Vector_Unit
);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute
);
195 MAKE_FUNCPTR(FcFontList
);
196 MAKE_FUNCPTR(FcFontSetDestroy
);
197 MAKE_FUNCPTR(FcInit
);
198 MAKE_FUNCPTR(FcObjectSetAdd
);
199 MAKE_FUNCPTR(FcObjectSetCreate
);
200 MAKE_FUNCPTR(FcObjectSetDestroy
);
201 MAKE_FUNCPTR(FcPatternCreate
);
202 MAKE_FUNCPTR(FcPatternDestroy
);
203 MAKE_FUNCPTR(FcPatternGetBool
);
204 MAKE_FUNCPTR(FcPatternGetInteger
);
205 MAKE_FUNCPTR(FcPatternGetString
);
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
242 FT_Short internal_leading
;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
249 FT_Short height
, width
;
250 FT_Pos size
, x_ppem
, y_ppem
;
256 NEWTEXTMETRICEXW ntm
;
260 typedef struct tagFace
{
262 unsigned int refcount
;
267 DWORD font_data_size
;
271 FT_Fixed font_version
;
273 Bitmap_Size size
; /* set if face is a bitmap */
274 DWORD flags
; /* ADDFONT flags */
275 struct tagFamily
*family
;
276 /* Cached data for Enum */
277 struct enum_data
*cached_enum_data
;
280 #define ADDFONT_EXTERNAL_FONT 0x01
281 #define ADDFONT_ALLOW_BITMAP 0x02
282 #define ADDFONT_ADD_TO_CACHE 0x04
283 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
284 #define ADDFONT_VERTICAL_FONT 0x10
285 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
287 typedef struct tagFamily
{
289 unsigned int refcount
;
293 struct list
*replacement
;
298 ABC abc
; /* metrics of the unrotated char */
314 typedef struct tagGdiFont GdiFont
;
324 struct list unused_entry
;
325 unsigned int refcount
;
328 OUTLINETEXTMETRICW
*potm
;
329 DWORD total_kern_pairs
;
330 KERNINGPAIR
*kern_pairs
;
331 struct list child_fonts
;
333 /* the following members can be accessed without locking, they are never modified after creation */
335 struct font_mapping
*mapping
;
351 UINT ntmCellHeight
, ntmAvgWidth
;
360 const WCHAR
*font_name
;
365 struct enum_charset_element
{
368 WCHAR name
[LF_FACESIZE
];
371 struct enum_charset_list
{
373 struct enum_charset_element element
[32];
376 #define GM_BLOCK_SIZE 128
377 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
379 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
380 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
381 static unsigned int unused_font_count
;
382 #define UNUSED_CACHE_SIZE 10
383 static struct list system_links
= LIST_INIT(system_links
);
385 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
387 static struct list font_list
= LIST_INIT(font_list
);
389 struct freetype_physdev
391 struct gdi_physdev dev
;
395 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
397 return (struct freetype_physdev
*)dev
;
400 static const struct gdi_dc_funcs freetype_funcs
;
402 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
403 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
404 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
406 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
407 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
408 'W','i','n','d','o','w','s','\\',
409 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
410 'F','o','n','t','s','\0'};
412 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
413 'W','i','n','d','o','w','s',' ','N','T','\\',
414 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
415 'F','o','n','t','s','\0'};
417 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
418 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
419 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
420 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
422 static const WCHAR
* const SystemFontValues
[] = {
429 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
430 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
432 /* Interesting and well-known (frequently-assumed!) font names */
433 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
434 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 };
435 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
436 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
437 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
438 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
439 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
440 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
442 static const WCHAR arial
[] = {'A','r','i','a','l',0};
443 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
444 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};
445 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};
446 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
447 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
448 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
449 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
450 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
451 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
453 static const WCHAR
*default_serif_list
[] =
457 bitstream_vera_serif
,
461 static const WCHAR
*default_fixed_list
[] =
465 bitstream_vera_sans_mono
,
469 static const WCHAR
*default_sans_list
[] =
482 typedef struct tagFontSubst
{
488 /* Registry font cache key and value names */
489 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
490 'F','o','n','t','s',0};
491 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
492 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
493 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
494 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
495 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
496 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
497 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
498 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
499 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
500 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
501 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
502 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
503 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
504 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
505 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
518 static struct list mappings_list
= LIST_INIT( mappings_list
);
520 static UINT default_aa_flags
;
521 static HKEY hkey_font_cache
;
523 static CRITICAL_SECTION freetype_cs
;
524 static CRITICAL_SECTION_DEBUG critsect_debug
=
527 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
528 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
530 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
532 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
534 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
535 static BOOL use_default_fallback
= FALSE
;
537 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
538 static BOOL
get_outline_text_metrics(GdiFont
*font
);
539 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
540 static void remove_face_from_cache( Face
*face
);
542 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
543 'W','i','n','d','o','w','s',' ','N','T','\\',
544 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
545 'S','y','s','t','e','m','L','i','n','k',0};
547 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
548 'F','o','n','t','L','i','n','k','\\',
549 'S','y','s','t','e','m','L','i','n','k',0};
551 /****************************************
552 * Notes on .fon files
554 * The fonts System, FixedSys and Terminal are special. There are typically multiple
555 * versions installed for different resolutions and codepages. Windows stores which one to use
556 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
558 * FIXEDFON.FON FixedSys
560 * OEMFONT.FON Terminal
561 * LogPixels Current dpi set by the display control panel applet
562 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
563 * also has a LogPixels value that appears to mirror this)
565 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
566 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
567 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
568 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
569 * so that makes sense.
571 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
572 * to be mapped into the registry on Windows 2000 at least).
575 * ega80woa.fon=ega80850.fon
576 * ega40woa.fon=ega40850.fon
577 * cga80woa.fon=cga80850.fon
578 * cga40woa.fon=cga40850.fon
581 /* These are all structures needed for the GSUB table */
583 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
584 #define TATEGAKI_LOWER_BOUND 0x02F1
600 GSUB_ScriptRecord ScriptRecord
[1];
606 } GSUB_LangSysRecord
;
611 GSUB_LangSysRecord LangSysRecord
[1];
615 WORD LookupOrder
; /* Reserved */
616 WORD ReqFeatureIndex
;
618 WORD FeatureIndex
[1];
624 } GSUB_FeatureRecord
;
628 GSUB_FeatureRecord FeatureRecord
[1];
632 WORD FeatureParams
; /* Reserved */
634 WORD LookupListIndex
[1];
653 } GSUB_CoverageFormat1
;
658 WORD StartCoverageIndex
;
664 GSUB_RangeRecord RangeRecord
[1];
665 } GSUB_CoverageFormat2
;
668 WORD SubstFormat
; /* = 1 */
671 } GSUB_SingleSubstFormat1
;
674 WORD SubstFormat
; /* = 2 */
678 }GSUB_SingleSubstFormat2
;
680 #ifdef HAVE_CARBON_CARBON_H
681 static char *find_cache_dir(void)
685 static char cached_path
[MAX_PATH
];
686 static const char *wine
= "/Wine", *fonts
= "/Fonts";
688 if(*cached_path
) return cached_path
;
690 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
693 WARN("can't create cached data folder\n");
696 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
699 WARN("can't create cached data path\n");
703 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
705 ERR("Could not create full path\n");
709 strcat(cached_path
, wine
);
711 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
713 WARN("Couldn't mkdir %s\n", cached_path
);
717 strcat(cached_path
, fonts
);
718 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
720 WARN("Couldn't mkdir %s\n", cached_path
);
727 /******************************************************************
730 * Extracts individual TrueType font files from a Mac suitcase font
731 * and saves them into the user's caches directory (see
733 * Returns a NULL terminated array of filenames.
735 * We do this because they are apps that try to read ttf files
736 * themselves and they don't like Mac suitcase files.
738 static char **expand_mac_font(const char *path
)
745 const char *filename
;
749 unsigned int size
, max_size
;
752 TRACE("path %s\n", path
);
754 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
757 WARN("failed to get ref\n");
761 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
764 TRACE("no data fork, so trying resource fork\n");
765 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
768 TRACE("unable to open resource fork\n");
775 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
778 CloseResFile(res_ref
);
782 out_dir
= find_cache_dir();
784 filename
= strrchr(path
, '/');
785 if(!filename
) filename
= path
;
788 /* output filename has the form out_dir/filename_%04x.ttf */
789 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
796 unsigned short *num_faces_ptr
, num_faces
, face
;
799 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
801 fond
= Get1IndResource(fond_res
, idx
);
803 TRACE("got fond resource %d\n", idx
);
806 fam_rec
= *(FamRec
**)fond
;
807 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
808 num_faces
= GET_BE_WORD(*num_faces_ptr
);
810 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
811 TRACE("num faces %04x\n", num_faces
);
812 for(face
= 0; face
< num_faces
; face
++, assoc
++)
815 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
816 unsigned short size
, font_id
;
819 size
= GET_BE_WORD(assoc
->fontSize
);
820 font_id
= GET_BE_WORD(assoc
->fontID
);
823 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
827 TRACE("trying to load sfnt id %04x\n", font_id
);
828 sfnt
= GetResource(sfnt_res
, font_id
);
831 TRACE("can't get sfnt resource %04x\n", font_id
);
835 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
840 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
842 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
843 if(fd
!= -1 || errno
== EEXIST
)
847 unsigned char *sfnt_data
;
850 sfnt_data
= *(unsigned char**)sfnt
;
851 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
855 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
858 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
860 ret
.array
[ret
.size
++] = output
;
864 WARN("unable to create %s\n", output
);
865 HeapFree(GetProcessHeap(), 0, output
);
868 ReleaseResource(sfnt
);
871 ReleaseResource(fond
);
874 CloseResFile(res_ref
);
879 #endif /* HAVE_CARBON_CARBON_H */
881 static inline BOOL
is_win9x(void)
883 return GetVersion() & 0x80000000;
886 This function builds an FT_Fixed from a double. It fails if the absolute
887 value of the float number is greater than 32768.
889 static inline FT_Fixed
FT_FixedFromFloat(double f
)
895 This function builds an FT_Fixed from a FIXED. It simply put f.value
896 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
898 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
900 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
903 static BOOL
is_hinting_enabled(void)
905 static int enabled
= -1;
909 /* Use the >= 2.2.0 function if available */
910 if (pFT_Get_TrueType_Engine_Type
)
912 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
913 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
915 #ifdef FT_DRIVER_HAS_HINTER
918 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
919 FT_Module mod
= pFT_Get_Module(library
, "truetype");
920 enabled
= (mod
&& FT_DRIVER_HAS_HINTER(mod
));
923 else enabled
= FALSE
;
924 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
929 static BOOL
is_subpixel_rendering_enabled( void )
931 #ifdef HAVE_FREETYPE_FTLCDFIL_H
932 static int enabled
= -1;
935 enabled
= (pFT_Library_SetLcdFilter
&&
936 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
937 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
946 static const struct list
*get_face_list_from_family(const Family
*family
)
948 if (!list_empty(&family
->faces
))
949 return &family
->faces
;
951 return family
->replacement
;
954 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
960 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
962 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
964 const struct list
*face_list
;
965 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
967 face_list
= get_face_list_from_family(family
);
968 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
972 file
= strrchrW(face
->file
, '/');
977 if(strcmpiW(file
, file_name
)) continue;
985 static Family
*find_family_from_name(const WCHAR
*name
)
989 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
991 if(!strcmpiW(family
->FamilyName
, name
))
998 static Family
*find_family_from_any_name(const WCHAR
*name
)
1002 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1004 if(!strcmpiW(family
->FamilyName
, name
))
1006 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1013 static void DumpSubstList(void)
1017 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1019 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1020 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1021 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1023 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1024 debugstr_w(psub
->to
.name
));
1029 static LPWSTR
strdupW(LPCWSTR p
)
1032 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1033 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1034 memcpy(ret
, p
, len
);
1038 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1043 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1045 if(!strcmpiW(element
->from
.name
, from_name
) &&
1046 (element
->from
.charset
== from_charset
||
1047 element
->from
.charset
== -1))
1054 #define ADD_FONT_SUBST_FORCE 1
1056 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1058 FontSubst
*from_exist
, *to_exist
;
1060 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1062 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1064 list_remove(&from_exist
->entry
);
1065 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1066 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1067 HeapFree(GetProcessHeap(), 0, from_exist
);
1073 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1077 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1078 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1081 list_add_tail(subst_list
, &subst
->entry
);
1086 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1087 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1088 HeapFree(GetProcessHeap(), 0, subst
);
1092 static WCHAR
*towstr(UINT cp
, const char *str
)
1097 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1098 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1099 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1103 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1105 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1106 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1107 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1111 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1113 CHAR
*p
= strrchr(str
, ',');
1117 nc
->charset
= strtol(p
+1, NULL
, 10);
1120 nc
->name
= towstr(CP_ACP
, str
);
1123 static void LoadSubstList(void)
1127 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1131 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1132 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1133 &hkey
) == ERROR_SUCCESS
) {
1135 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1136 &valuelen
, &datalen
, NULL
, NULL
);
1138 valuelen
++; /* returned value doesn't include room for '\0' */
1139 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1140 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1144 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1145 &dlen
) == ERROR_SUCCESS
) {
1146 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1148 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1149 split_subst_info(&psub
->from
, value
);
1150 split_subst_info(&psub
->to
, data
);
1152 /* Win 2000 doesn't allow mapping between different charsets
1153 or mapping of DEFAULT_CHARSET */
1154 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1155 psub
->to
.charset
== DEFAULT_CHARSET
) {
1156 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1157 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1158 HeapFree(GetProcessHeap(), 0, psub
);
1160 add_font_subst(&font_subst_list
, psub
, 0);
1162 /* reset dlen and vlen */
1166 HeapFree(GetProcessHeap(), 0, data
);
1167 HeapFree(GetProcessHeap(), 0, value
);
1173 /*****************************************************************
1174 * get_name_table_entry
1176 * Supply the platform, encoding, language and name ids in req
1177 * and if the name exists the function will fill in the string
1178 * and string_len members. The string is owned by FreeType so
1179 * don't free it. Returns TRUE if the name is found else FALSE.
1181 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1184 FT_UInt num_names
, name_index
;
1186 if(FT_IS_SFNT(ft_face
))
1188 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1190 for(name_index
= 0; name_index
< num_names
; name_index
++)
1192 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1194 if((name
.platform_id
== req
->platform_id
) &&
1195 ((name
.encoding_id
== TT_MS_ID_UNICODE_CS
) || (name
.encoding_id
== TT_MS_ID_SYMBOL_CS
)) &&
1196 (name
.language_id
== req
->language_id
) &&
1197 (name
.name_id
== req
->name_id
))
1199 req
->string
= name
.string
;
1200 req
->string_len
= name
.string_len
;
1207 req
->string_len
= 0;
1211 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1216 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1217 name
.language_id
= language_id
;
1218 name
.name_id
= name_id
;
1220 if(get_name_table_entry(ft_face
, &name
))
1224 /* String is not nul terminated and string_len is a byte length. */
1225 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1226 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1228 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1229 ret
[i
] = GET_BE_WORD(*tmp
);
1232 TRACE("Got localised name %s\n", debugstr_w(ret
));
1238 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1240 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1241 if (f1
->scalable
) return TRUE
;
1242 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1243 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1246 static void release_family( Family
*family
)
1248 if (--family
->refcount
) return;
1249 assert( list_empty( &family
->faces
));
1250 list_remove( &family
->entry
);
1251 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1252 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1253 HeapFree( GetProcessHeap(), 0, family
);
1256 static void release_face( Face
*face
)
1258 if (--face
->refcount
) return;
1261 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1262 list_remove( &face
->entry
);
1263 release_family( face
->family
);
1265 HeapFree( GetProcessHeap(), 0, face
->file
);
1266 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1267 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1268 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1269 HeapFree( GetProcessHeap(), 0, face
);
1272 static inline int style_order(const Face
*face
)
1274 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1282 case NTM_BOLD
| NTM_ITALIC
:
1285 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1286 debugstr_w(face
->family
->FamilyName
),
1287 debugstr_w(face
->StyleName
),
1293 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1297 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1299 if (faces_equal( face
, cursor
))
1301 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1302 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1303 cursor
->font_version
, face
->font_version
);
1305 if (face
->font_version
<= cursor
->font_version
)
1307 TRACE("Original font %s is newer so skipping %s\n",
1308 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1313 TRACE("Replacing original %s with %s\n",
1314 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1315 list_add_before( &cursor
->entry
, &face
->entry
);
1316 face
->family
= family
;
1319 release_face( cursor
);
1324 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1326 if (style_order( face
) < style_order( cursor
)) break;
1329 list_add_before( &cursor
->entry
, &face
->entry
);
1330 face
->family
= family
;
1336 /****************************************************************
1337 * NB This function stores the ptrs to the strings to save copying.
1338 * Don't free them after calling.
1340 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1342 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1343 family
->refcount
= 1;
1344 family
->FamilyName
= name
;
1345 family
->EnglishName
= english_name
;
1346 list_init( &family
->faces
);
1347 family
->replacement
= &family
->faces
;
1348 list_add_tail( &font_list
, &family
->entry
);
1353 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1355 DWORD type
, size
= sizeof(DWORD
);
1357 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1358 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1361 return ERROR_BAD_CONFIGURATION
;
1363 return ERROR_SUCCESS
;
1366 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1368 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1371 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1373 DWORD needed
, strike_index
= 0;
1376 /* If we have a File Name key then this is a real font, not just the parent
1377 key of a bunch of non-scalable strikes */
1378 needed
= buffer_size
;
1379 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1382 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1383 face
->cached_enum_data
= NULL
;
1384 face
->family
= NULL
;
1387 face
->file
= strdupW( buffer
);
1388 face
->StyleName
= strdupW(face_name
);
1390 needed
= buffer_size
;
1391 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1392 face
->FullName
= strdupW( buffer
);
1394 face
->FullName
= NULL
;
1396 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1397 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1398 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1399 reg_load_dword(hkey_face
, face_flags_value
, (DWORD
*)&face
->flags
);
1401 needed
= sizeof(face
->fs
);
1402 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1404 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1406 face
->scalable
= TRUE
;
1407 memset(&face
->size
, 0, sizeof(face
->size
));
1411 face
->scalable
= FALSE
;
1412 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1413 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1414 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1415 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1416 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1418 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1419 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1420 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1423 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1424 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1425 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1426 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1428 if (insert_face_in_family_list(face
, family
))
1429 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1431 release_face( face
);
1434 /* load bitmap strikes */
1436 needed
= buffer_size
;
1437 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1439 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1441 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1442 RegCloseKey(hkey_strike
);
1444 needed
= buffer_size
;
1448 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1450 DWORD size
, family_index
= 0;
1455 size
= sizeof(buffer
);
1456 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1458 WCHAR
*english_family
= NULL
;
1459 WCHAR
*family_name
= strdupW( buffer
);
1460 DWORD face_index
= 0;
1462 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1463 TRACE("opened family key %s\n", debugstr_w(family_name
));
1464 size
= sizeof(buffer
);
1465 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1466 english_family
= strdupW( buffer
);
1468 family
= create_family(family_name
, english_family
);
1472 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1473 subst
->from
.name
= strdupW(english_family
);
1474 subst
->from
.charset
= -1;
1475 subst
->to
.name
= strdupW(family_name
);
1476 subst
->to
.charset
= -1;
1477 add_font_subst(&font_subst_list
, subst
, 0);
1480 size
= sizeof(buffer
);
1481 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1483 WCHAR
*face_name
= strdupW( buffer
);
1486 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1488 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1489 RegCloseKey(hkey_face
);
1491 HeapFree( GetProcessHeap(), 0, face_name
);
1492 size
= sizeof(buffer
);
1494 RegCloseKey(hkey_family
);
1495 release_family( family
);
1496 size
= sizeof(buffer
);
1500 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1503 HKEY hkey_wine_fonts
;
1505 /* We don't want to create the fonts key as volatile, so open this first */
1506 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1507 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1508 if(ret
!= ERROR_SUCCESS
)
1510 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1514 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1515 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1516 RegCloseKey(hkey_wine_fonts
);
1520 static void add_face_to_cache(Face
*face
)
1522 HKEY hkey_family
, hkey_face
;
1523 WCHAR
*face_key_name
;
1525 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1526 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1527 if(face
->family
->EnglishName
)
1528 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1529 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1532 face_key_name
= face
->StyleName
;
1535 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1536 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1537 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1539 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1542 HeapFree(GetProcessHeap(), 0, face_key_name
);
1544 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1545 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1547 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1548 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1550 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1551 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1552 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1553 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1555 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1559 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1560 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1561 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1562 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1563 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1564 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1566 RegCloseKey(hkey_face
);
1567 RegCloseKey(hkey_family
);
1570 static void remove_face_from_cache( Face
*face
)
1574 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1578 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1582 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1583 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1584 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1585 RegDeleteKeyW( hkey_family
, face_key_name
);
1586 HeapFree(GetProcessHeap(), 0, face_key_name
);
1588 RegCloseKey(hkey_family
);
1591 static WCHAR
*prepend_at(WCHAR
*family
)
1598 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1600 strcpyW(str
+ 1, family
);
1601 HeapFree(GetProcessHeap(), 0, family
);
1605 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1607 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1608 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1610 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1616 else if (!strcmpiW( *name
, *english
))
1618 HeapFree( GetProcessHeap(), 0, *english
);
1624 *name
= prepend_at( *name
);
1625 *english
= prepend_at( *english
);
1629 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1632 WCHAR
*name
, *english_name
;
1634 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1636 family
= find_family_from_name( name
);
1640 family
= create_family( name
, english_name
);
1643 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1644 subst
->from
.name
= strdupW( english_name
);
1645 subst
->from
.charset
= -1;
1646 subst
->to
.name
= strdupW( name
);
1647 subst
->to
.charset
= -1;
1648 add_font_subst( &font_subst_list
, subst
, 0 );
1653 HeapFree( GetProcessHeap(), 0, name
);
1654 HeapFree( GetProcessHeap(), 0, english_name
);
1661 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1663 FT_Fixed version
= 0;
1666 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1667 if (header
) version
= header
->Font_Revision
;
1672 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1675 FT_ULong table_size
= 0;
1677 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1678 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1679 if (flags
== 0) flags
= NTM_REGULAR
;
1681 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1682 flags
|= NTM_PS_OPENTYPE
;
1687 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1689 int internal_leading
= 0;
1690 FT_WinFNT_HeaderRec winfnt_header
;
1692 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1693 internal_leading
= winfnt_header
.internal_leading
;
1695 return internal_leading
;
1698 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1703 FT_WinFNT_HeaderRec winfnt_header
;
1706 memset( fs
, 0, sizeof(*fs
) );
1708 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1711 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1712 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1713 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1714 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1716 if (os2
->version
== 0)
1718 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1719 fs
->fsCsb
[0] = FS_LATIN1
;
1721 fs
->fsCsb
[0] = FS_SYMBOL
;
1725 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1726 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1731 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1733 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1734 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1735 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1740 if (fs
->fsCsb
[0] == 0)
1742 /* let's see if we can find any interesting cmaps */
1743 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1745 switch (ft_face
->charmaps
[i
]->encoding
)
1747 case FT_ENCODING_UNICODE
:
1748 case FT_ENCODING_APPLE_ROMAN
:
1749 fs
->fsCsb
[0] |= FS_LATIN1
;
1751 case FT_ENCODING_MS_SYMBOL
:
1752 fs
->fsCsb
[0] |= FS_SYMBOL
;
1761 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1764 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1765 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1768 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1769 if (!face
->StyleName
)
1770 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1771 if (!face
->StyleName
)
1773 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1776 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1777 if (!face
->FullName
)
1778 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1779 if (flags
& ADDFONT_VERTICAL_FONT
)
1780 face
->FullName
= prepend_at( face
->FullName
);
1784 face
->file
= towstr( CP_UNIXCP
, file
);
1785 face
->font_data_ptr
= NULL
;
1786 face
->font_data_size
= 0;
1791 face
->font_data_ptr
= font_data_ptr
;
1792 face
->font_data_size
= font_data_size
;
1795 face
->face_index
= face_index
;
1796 get_fontsig( ft_face
, &face
->fs
);
1797 face
->ntmFlags
= get_ntm_flags( ft_face
);
1798 face
->font_version
= get_font_version( ft_face
);
1800 if (FT_IS_SCALABLE( ft_face
))
1802 memset( &face
->size
, 0, sizeof(face
->size
) );
1803 face
->scalable
= TRUE
;
1807 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1808 size
->height
, size
->width
, size
->size
>> 6,
1809 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1810 face
->size
.height
= size
->height
;
1811 face
->size
.width
= size
->width
;
1812 face
->size
.size
= size
->size
;
1813 face
->size
.x_ppem
= size
->x_ppem
;
1814 face
->size
.y_ppem
= size
->y_ppem
;
1815 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1816 face
->scalable
= FALSE
;
1819 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1820 face
->flags
= flags
;
1821 face
->family
= NULL
;
1822 face
->cached_enum_data
= NULL
;
1824 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1825 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1826 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1827 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1832 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1833 FT_Long face_index
, DWORD flags
)
1838 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
1839 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
1840 if (insert_face_in_family_list( face
, family
))
1842 if (flags
& ADDFONT_ADD_TO_CACHE
)
1843 add_face_to_cache( face
);
1845 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1846 debugstr_w(face
->StyleName
));
1848 release_face( face
);
1849 release_family( family
);
1852 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1853 FT_Long face_index
, BOOL allow_bitmap
)
1861 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1862 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1866 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1867 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1872 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1876 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1877 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1879 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1883 if (!FT_IS_SFNT( ft_face
))
1885 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1887 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1893 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1894 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1895 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1897 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1898 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1902 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1903 we don't want to load these. */
1904 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1908 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1910 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1916 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1918 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1924 pFT_Done_Face( ft_face
);
1928 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1931 FT_Long face_index
= 0, num_faces
;
1934 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1935 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1937 #ifdef HAVE_CARBON_CARBON_H
1940 char **mac_list
= expand_mac_font(file
);
1943 BOOL had_one
= FALSE
;
1945 for(cursor
= mac_list
; *cursor
; cursor
++)
1948 AddFontToList(*cursor
, NULL
, 0, flags
);
1949 HeapFree(GetProcessHeap(), 0, *cursor
);
1951 HeapFree(GetProcessHeap(), 0, mac_list
);
1956 #endif /* HAVE_CARBON_CARBON_H */
1959 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
1960 if (!ft_face
) return 0;
1962 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1964 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1965 pFT_Done_Face(ft_face
);
1969 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
1972 if (FT_HAS_VERTICAL(ft_face
))
1974 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
1975 flags
| ADDFONT_VERTICAL_FONT
);
1979 num_faces
= ft_face
->num_faces
;
1980 pFT_Done_Face(ft_face
);
1981 } while(num_faces
> ++face_index
);
1985 static int remove_font_resource( const char *file
, DWORD flags
)
1987 Family
*family
, *family_next
;
1988 Face
*face
, *face_next
;
1990 struct stat st
, st2
;
1993 if (stat( file
, &st
) == -1) return 0;
1994 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
1997 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
1999 if (!face
->file
) continue;
2000 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2001 filename
= strWtoA( CP_UNIXCP
, face
->file
);
2002 if (!stat( filename
, &st2
) && st
.st_dev
== st2
.st_dev
&& st
.st_ino
== st2
.st_ino
)
2004 TRACE( "removing matching face %s\n", debugstr_w(face
->file
) );
2005 release_face( face
);
2008 HeapFree( GetProcessHeap(), 0, filename
);
2010 release_family( family
);
2015 static void DumpFontList(void)
2020 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2021 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2022 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2023 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2025 TRACE(" %d", face
->size
.height
);
2032 /***********************************************************
2033 * The replacement list is a way to map an entire font
2034 * family onto another family. For example adding
2036 * [HKCU\Software\Wine\Fonts\Replacements]
2037 * "Wingdings"="Winedings"
2039 * would enumerate the Winedings font both as Winedings and
2040 * Wingdings. However if a real Wingdings font is present the
2041 * replacement does not take place.
2044 static void LoadReplaceList(void)
2047 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2051 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2052 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2054 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2055 &valuelen
, &datalen
, NULL
, NULL
);
2057 valuelen
++; /* returned value doesn't include room for '\0' */
2058 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2059 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2063 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2064 &dlen
) == ERROR_SUCCESS
) {
2065 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2066 /* "NewName"="Oldname" */
2067 if(!find_family_from_any_name(value
))
2069 Family
* const family
= find_family_from_any_name(data
);
2072 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2073 if (new_family
!= NULL
)
2075 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2076 new_family
->FamilyName
= strdupW(value
);
2077 new_family
->EnglishName
= NULL
;
2078 list_init(&new_family
->faces
);
2079 new_family
->replacement
= &family
->faces
;
2080 list_add_tail(&font_list
, &new_family
->entry
);
2085 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2090 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2092 /* reset dlen and vlen */
2096 HeapFree(GetProcessHeap(), 0, data
);
2097 HeapFree(GetProcessHeap(), 0, value
);
2102 static const WCHAR
*font_links_list
[] =
2104 Lucida_Sans_Unicode
,
2105 Microsoft_Sans_Serif
,
2109 static const struct font_links_defaults_list
2111 /* Keyed off substitution for "MS Shell Dlg" */
2112 const WCHAR
*shelldlg
;
2113 /* Maximum of four substitutes, plus terminating NULL pointer */
2114 const WCHAR
*substitutes
[5];
2115 } font_links_defaults_list
[] =
2117 /* Non East-Asian */
2118 { Tahoma
, /* FIXME unverified ordering */
2119 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2121 /* Below lists are courtesy of
2122 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2126 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2128 /* Chinese Simplified */
2130 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2134 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2136 /* Chinese Traditional */
2138 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2143 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2145 SYSTEM_LINKS
*font_link
;
2147 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2149 if(!strcmpiW(font_link
->font_name
, name
))
2156 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2167 SYSTEM_LINKS
*font_link
;
2169 psub
= get_font_subst(&font_subst_list
, name
, -1);
2170 /* Don't store fonts that are only substitutes for other fonts */
2173 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2177 font_link
= find_font_link(name
);
2178 if (font_link
== NULL
)
2180 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2181 font_link
->font_name
= strdupW(name
);
2182 list_init(&font_link
->links
);
2183 list_add_tail(&system_links
, &font_link
->entry
);
2186 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2187 for (i
= 0; values
[i
] != NULL
; i
++)
2189 const struct list
*face_list
;
2190 CHILD_FONT
*child_font
;
2193 if (!strcmpiW(name
,value
))
2195 psub
= get_font_subst(&font_subst_list
, value
, -1);
2197 value
= psub
->to
.name
;
2198 family
= find_family_from_name(value
);
2202 /* Use first extant filename for this Family */
2203 face_list
= get_face_list_from_family(family
);
2204 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2208 file
= strrchrW(face
->file
, '/');
2217 face
= find_face_from_filename(file
, value
);
2220 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2224 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2225 child_font
->face
= face
;
2226 child_font
->font
= NULL
;
2227 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2228 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2229 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2230 child_font
->face
->face_index
);
2231 list_add_tail(&font_link
->links
, &child_font
->entry
);
2233 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2239 /*************************************************************
2242 static BOOL
init_system_links(void)
2246 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2247 WCHAR
*value
, *data
;
2248 WCHAR
*entry
, *next
;
2249 SYSTEM_LINKS
*font_link
, *system_font_link
;
2250 CHILD_FONT
*child_font
;
2251 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2252 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2253 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2258 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2260 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2261 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2262 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2263 val_len
= max_val
+ 1;
2264 data_len
= max_data
;
2266 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2268 psub
= get_font_subst(&font_subst_list
, value
, -1);
2269 /* Don't store fonts that are only substitutes for other fonts */
2272 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2275 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2276 font_link
->font_name
= strdupW(value
);
2277 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2278 list_init(&font_link
->links
);
2279 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2282 CHILD_FONT
*child_font
;
2284 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2286 next
= entry
+ strlenW(entry
) + 1;
2288 face_name
= strchrW(entry
, ',');
2292 while(isspaceW(*face_name
))
2295 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2297 face_name
= psub
->to
.name
;
2299 face
= find_face_from_filename(entry
, face_name
);
2302 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2306 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2307 child_font
->face
= face
;
2308 child_font
->font
= NULL
;
2309 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2310 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2311 TRACE("Adding file %s index %ld\n",
2312 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2313 list_add_tail(&font_link
->links
, &child_font
->entry
);
2315 list_add_tail(&system_links
, &font_link
->entry
);
2317 val_len
= max_val
+ 1;
2318 data_len
= max_data
;
2321 HeapFree(GetProcessHeap(), 0, value
);
2322 HeapFree(GetProcessHeap(), 0, data
);
2327 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2329 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2333 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2335 const FontSubst
*psub2
;
2336 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2338 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2340 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2341 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2343 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2344 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2346 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2348 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2354 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2357 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2358 system_font_link
->font_name
= strdupW(System
);
2359 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2360 list_init(&system_font_link
->links
);
2362 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2365 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2366 child_font
->face
= face
;
2367 child_font
->font
= NULL
;
2368 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2369 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2370 TRACE("Found Tahoma in %s index %ld\n",
2371 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2372 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2374 font_link
= find_font_link(Tahoma
);
2375 if (font_link
!= NULL
)
2377 CHILD_FONT
*font_link_entry
;
2378 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2380 CHILD_FONT
*new_child
;
2381 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2382 new_child
->face
= font_link_entry
->face
;
2383 new_child
->font
= NULL
;
2384 new_child
->face
->refcount
++;
2385 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2386 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2387 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2390 list_add_tail(&system_links
, &system_font_link
->entry
);
2394 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2397 struct dirent
*dent
;
2398 char path
[MAX_PATH
];
2400 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2402 dir
= opendir(dirname
);
2404 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2407 while((dent
= readdir(dir
)) != NULL
) {
2408 struct stat statbuf
;
2410 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2413 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2415 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2417 if(stat(path
, &statbuf
) == -1)
2419 WARN("Can't stat %s\n", debugstr_a(path
));
2422 if(S_ISDIR(statbuf
.st_mode
))
2423 ReadFontDir(path
, external_fonts
);
2426 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2427 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2428 AddFontToList(path
, NULL
, 0, addfont_flags
);
2435 #ifdef SONAME_LIBFONTCONFIG
2437 static BOOL fontconfig_enabled
;
2439 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2445 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2446 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2448 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2452 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2453 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2454 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2455 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2456 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2462 static void init_fontconfig(void)
2464 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2468 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2472 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2473 LOAD_FUNCPTR(FcConfigSubstitute
);
2474 LOAD_FUNCPTR(FcFontList
);
2475 LOAD_FUNCPTR(FcFontSetDestroy
);
2476 LOAD_FUNCPTR(FcInit
);
2477 LOAD_FUNCPTR(FcObjectSetAdd
);
2478 LOAD_FUNCPTR(FcObjectSetCreate
);
2479 LOAD_FUNCPTR(FcObjectSetDestroy
);
2480 LOAD_FUNCPTR(FcPatternCreate
);
2481 LOAD_FUNCPTR(FcPatternDestroy
);
2482 LOAD_FUNCPTR(FcPatternGetBool
);
2483 LOAD_FUNCPTR(FcPatternGetInteger
);
2484 LOAD_FUNCPTR(FcPatternGetString
);
2489 FcPattern
*pattern
= pFcPatternCreate();
2490 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2491 default_aa_flags
= parse_aa_pattern( pattern
);
2492 pFcPatternDestroy( pattern
);
2493 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2494 fontconfig_enabled
= TRUE
;
2498 static void load_fontconfig_fonts(void)
2507 if (!fontconfig_enabled
) return;
2509 pat
= pFcPatternCreate();
2510 os
= pFcObjectSetCreate();
2511 pFcObjectSetAdd(os
, FC_FILE
);
2512 pFcObjectSetAdd(os
, FC_SCALABLE
);
2513 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2514 pFcObjectSetAdd(os
, FC_RGBA
);
2515 fontset
= pFcFontList(NULL
, pat
, os
);
2516 if(!fontset
) return;
2517 for(i
= 0; i
< fontset
->nfont
; i
++) {
2521 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2524 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2526 /* We're just interested in OT/TT fonts for now, so this hack just
2527 picks up the scalable fonts without extensions .pf[ab] to save time
2528 loading every other font */
2530 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2532 TRACE("not scalable\n");
2536 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2537 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2539 len
= strlen( file
);
2540 if(len
< 4) continue;
2541 ext
= &file
[ len
- 3 ];
2542 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2543 AddFontToList(file
, NULL
, 0,
2544 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2546 pFcFontSetDestroy(fontset
);
2547 pFcObjectSetDestroy(os
);
2548 pFcPatternDestroy(pat
);
2551 #elif defined(HAVE_CARBON_CARBON_H)
2553 static void load_mac_font_callback(const void *value
, void *context
)
2555 CFStringRef pathStr
= value
;
2559 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2560 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2561 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2563 TRACE("font file %s\n", path
);
2564 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2566 HeapFree(GetProcessHeap(), 0, path
);
2569 static void load_mac_fonts(void)
2571 CFStringRef removeDupesKey
;
2572 CFBooleanRef removeDupesValue
;
2573 CFDictionaryRef options
;
2574 CTFontCollectionRef col
;
2576 CFMutableSetRef paths
;
2579 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2580 removeDupesValue
= kCFBooleanTrue
;
2581 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2582 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2583 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2584 if (options
) CFRelease(options
);
2587 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2591 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2595 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2599 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2602 WARN("CFSetCreateMutable failed\n");
2607 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2609 CTFontDescriptorRef desc
;
2618 desc
= CFArrayGetValueAtIndex(descs
, i
);
2620 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2621 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2622 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2623 if (!font
) continue;
2625 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2632 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2634 if (status
!= noErr
) continue;
2636 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2639 ext
= CFURLCopyPathExtension(url
);
2642 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2643 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2652 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2654 if (!path
) continue;
2656 CFSetAddValue(paths
, path
);
2662 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2668 static char *get_data_dir_path( LPCWSTR file
)
2670 char *unix_name
= NULL
;
2671 const char *data_dir
= wine_get_data_dir();
2673 if (!data_dir
) data_dir
= wine_get_build_dir();
2677 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2679 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2680 strcpy(unix_name
, data_dir
);
2681 strcat(unix_name
, "/fonts/");
2683 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2688 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2691 char *unix_name
= get_data_dir_path( file
);
2695 EnterCriticalSection( &freetype_cs
);
2696 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2697 LeaveCriticalSection( &freetype_cs
);
2698 HeapFree(GetProcessHeap(), 0, unix_name
);
2703 static char *get_winfonts_dir_path(LPCWSTR file
)
2705 static const WCHAR slashW
[] = {'\\','\0'};
2706 WCHAR windowsdir
[MAX_PATH
];
2708 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2709 strcatW(windowsdir
, fontsW
);
2710 strcatW(windowsdir
, slashW
);
2711 strcatW(windowsdir
, file
);
2712 return wine_get_unix_file_name( windowsdir
);
2715 static void load_system_fonts(void)
2718 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2719 const WCHAR
* const *value
;
2721 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2724 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2725 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2726 strcatW(windowsdir
, fontsW
);
2727 for(value
= SystemFontValues
; *value
; value
++) {
2728 dlen
= sizeof(data
);
2729 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2733 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2734 if((unixname
= wine_get_unix_file_name(pathW
))) {
2735 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2736 HeapFree(GetProcessHeap(), 0, unixname
);
2739 load_font_from_data_dir(data
);
2746 /*************************************************************
2748 * This adds registry entries for any externally loaded fonts
2749 * (fonts from fontconfig or FontDirs). It also deletes entries
2750 * of no longer existing fonts.
2753 static void update_reg_entries(void)
2755 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2761 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2763 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2764 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2765 ERR("Can't create Windows font reg key\n");
2769 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2770 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2771 ERR("Can't create Windows font reg key\n");
2775 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2776 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2777 ERR("Can't create external font reg key\n");
2781 /* enumerate the fonts and add external ones to the two keys */
2783 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2784 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2786 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
2790 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2791 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2792 strcpyW(valueW
, face
->FullName
);
2796 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2797 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2798 strcpyW(valueW
, family
->FamilyName
);
2801 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
2802 path
= wine_get_dos_file_name( buffer
);
2803 HeapFree( GetProcessHeap(), 0, buffer
);
2807 else if ((file
= strrchrW(face
->file
, '/')))
2812 len
= strlenW(file
) + 1;
2813 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2814 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2815 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2817 HeapFree(GetProcessHeap(), 0, path
);
2818 HeapFree(GetProcessHeap(), 0, valueW
);
2822 if(external_key
) RegCloseKey(external_key
);
2823 if(win9x_key
) RegCloseKey(win9x_key
);
2824 if(winnt_key
) RegCloseKey(winnt_key
);
2828 static void delete_external_font_keys(void)
2830 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2831 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2835 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2836 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2837 ERR("Can't create Windows font reg key\n");
2841 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2842 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2843 ERR("Can't create Windows font reg key\n");
2847 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2848 ERR("Can't create external font reg key\n");
2852 /* Delete all external fonts added last time */
2854 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2855 &valuelen
, &datalen
, NULL
, NULL
);
2856 valuelen
++; /* returned value doesn't include room for '\0' */
2857 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2858 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2860 dlen
= datalen
* sizeof(WCHAR
);
2863 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2864 &dlen
) == ERROR_SUCCESS
) {
2866 RegDeleteValueW(winnt_key
, valueW
);
2867 RegDeleteValueW(win9x_key
, valueW
);
2868 /* reset dlen and vlen */
2872 HeapFree(GetProcessHeap(), 0, data
);
2873 HeapFree(GetProcessHeap(), 0, valueW
);
2875 /* Delete the old external fonts key */
2876 RegCloseKey(external_key
);
2877 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2880 if(win9x_key
) RegCloseKey(win9x_key
);
2881 if(winnt_key
) RegCloseKey(winnt_key
);
2884 /*************************************************************
2885 * WineEngAddFontResourceEx
2888 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2894 if (ft_handle
) /* do it only if we have freetype up and running */
2898 EnterCriticalSection( &freetype_cs
);
2900 if((unixname
= wine_get_unix_file_name(file
)))
2902 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2904 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2905 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2906 HeapFree(GetProcessHeap(), 0, unixname
);
2908 if (!ret
&& !strchrW(file
, '\\')) {
2909 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2910 if ((unixname
= get_winfonts_dir_path( file
)))
2912 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2913 HeapFree(GetProcessHeap(), 0, unixname
);
2915 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2916 if (!ret
&& (unixname
= get_data_dir_path( file
)))
2918 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2919 HeapFree(GetProcessHeap(), 0, unixname
);
2923 LeaveCriticalSection( &freetype_cs
);
2928 /*************************************************************
2929 * WineEngAddFontMemResourceEx
2932 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2936 if (ft_handle
) /* do it only if we have freetype up and running */
2938 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2940 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2941 memcpy(pFontCopy
, pbFont
, cbFont
);
2943 EnterCriticalSection( &freetype_cs
);
2944 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2945 LeaveCriticalSection( &freetype_cs
);
2949 TRACE("AddFontToList failed\n");
2950 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2953 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2954 * For now return something unique but quite random
2956 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2957 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2964 /*************************************************************
2965 * WineEngRemoveFontResourceEx
2968 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2974 if (ft_handle
) /* do it only if we have freetype up and running */
2978 EnterCriticalSection( &freetype_cs
);
2980 if ((unixname
= wine_get_unix_file_name(file
)))
2982 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2984 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2985 ret
= remove_font_resource( unixname
, addfont_flags
);
2986 HeapFree(GetProcessHeap(), 0, unixname
);
2988 if (!ret
&& !strchrW(file
, '\\'))
2990 if ((unixname
= get_winfonts_dir_path( file
)))
2992 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2993 HeapFree(GetProcessHeap(), 0, unixname
);
2995 if (!ret
&& (unixname
= get_data_dir_path( file
)))
2997 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2998 HeapFree(GetProcessHeap(), 0, unixname
);
3002 LeaveCriticalSection( &freetype_cs
);
3007 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3013 if (!font_file
) return NULL
;
3015 file_len
= strlenW( font_file
);
3017 if (font_path
&& font_path
[0])
3019 int path_len
= strlenW( font_path
);
3020 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3021 if (!fullname
) return NULL
;
3022 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3023 fullname
[path_len
] = '\\';
3024 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3028 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3029 if (!len
) return NULL
;
3030 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3031 if (!fullname
) return NULL
;
3032 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3035 unix_name
= wine_get_unix_file_name( fullname
);
3036 HeapFree( GetProcessHeap(), 0, fullname
);
3040 #include <pshpack1.h>
3043 WORD num_of_resources
;
3047 CHAR dfCopyright
[60];
3053 WORD dfInternalLeading
;
3054 WORD dfExternalLeading
;
3062 BYTE dfPitchAndFamily
;
3073 CHAR szFaceName
[LF_FACESIZE
];
3076 #include <poppack.h>
3078 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3079 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3081 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3083 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3085 WCHAR
*name
, *english_name
;
3087 NEWTEXTMETRICEXW ntm
;
3090 if (!ft_face
) return FALSE
;
3091 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3092 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3093 pFT_Done_Face( ft_face
);
3095 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3096 release_face( face
);
3097 HeapFree( GetProcessHeap(), 0, name
);
3098 HeapFree( GetProcessHeap(), 0, english_name
);
3100 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3102 memset( fd
, 0, sizeof(*fd
) );
3104 fd
->num_of_resources
= 1;
3106 fd
->dfVersion
= 0x200;
3107 fd
->dfSize
= sizeof(*fd
);
3108 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3109 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3110 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3112 fd
->dfHorizRes
= 72;
3113 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3114 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3115 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3116 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3117 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3118 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3119 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3120 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3122 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3123 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3124 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3125 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3126 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3127 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3128 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3129 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3130 fd
->dfWidthBytes
= 0;
3132 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3134 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3139 #define NE_FFLAGS_LIBMODULE 0x8000
3140 #define NE_OSFLAGS_WINDOWS 0x02
3142 static const char dos_string
[0x40] = "This is a TrueType resource file";
3143 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3145 #include <pshpack2.h>
3166 struct ne_typeinfo fontdir_type
;
3167 struct ne_nameinfo fontdir_name
;
3168 struct ne_typeinfo scalable_type
;
3169 struct ne_nameinfo scalable_name
;
3171 BYTE fontdir_res_name
[8];
3174 #include <poppack.h>
3176 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3180 DWORD size
, written
;
3182 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3183 char *font_fileA
, *last_part
, *ext
;
3184 IMAGE_DOS_HEADER dos
;
3185 IMAGE_OS2_HEADER ne
=
3187 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3189 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3190 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3192 struct rsrc_tab rsrc_tab
=
3196 { 0, 0, 0x0c50, 0x2c, 0 },
3198 { 0, 0, 0x0c50, 0x8001, 0 },
3200 { 7,'F','O','N','T','D','I','R'}
3203 memset( &dos
, 0, sizeof(dos
) );
3204 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3205 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3207 /* import name is last part\0, resident name is last part without extension
3208 non-resident name is "FONTRES:" + lfFaceName */
3210 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3211 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3212 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3214 last_part
= strrchr( font_fileA
, '\\' );
3215 if (last_part
) last_part
++;
3216 else last_part
= font_fileA
;
3217 import_name_len
= strlen( last_part
) + 1;
3219 ext
= strchr( last_part
, '.' );
3220 if (ext
) res_name_len
= ext
- last_part
;
3221 else res_name_len
= import_name_len
- 1;
3223 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3225 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3226 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3227 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3228 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3230 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3232 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3233 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3234 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3235 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3237 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3238 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3242 HeapFree( GetProcessHeap(), 0, font_fileA
);
3246 memcpy( ptr
, &dos
, sizeof(dos
) );
3247 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3248 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3250 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3251 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3253 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3254 *ptr
++ = res_name_len
;
3255 memcpy( ptr
, last_part
, res_name_len
);
3257 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3258 *ptr
++ = import_name_len
;
3259 memcpy( ptr
, last_part
, import_name_len
);
3261 ptr
= start
+ ne
.ne_nrestab
;
3262 *ptr
++ = non_res_name_len
;
3263 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3264 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3266 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3267 memcpy( ptr
, font_fileA
, font_file_len
);
3269 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3270 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3272 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3273 if (file
!= INVALID_HANDLE_VALUE
)
3275 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3277 CloseHandle( file
);
3280 HeapFree( GetProcessHeap(), 0, start
);
3281 HeapFree( GetProcessHeap(), 0, font_fileA
);
3286 /*************************************************************
3287 * WineEngCreateScalableFontResource
3290 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3291 LPCWSTR font_file
, LPCWSTR font_path
)
3293 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3294 struct fontdir fontdir
;
3297 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3298 SetLastError( ERROR_INVALID_PARAMETER
);
3301 if (hidden
) fontdir
.dfType
|= 0x80;
3302 ret
= create_fot( resource
, font_file
, &fontdir
);
3305 HeapFree( GetProcessHeap(), 0, unix_name
);
3309 static const struct nls_update_font_list
3311 UINT ansi_cp
, oem_cp
;
3312 const char *oem
, *fixed
, *system
;
3313 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3314 /* these are for font substitutes */
3315 const char *shelldlg
, *tmsrmn
;
3316 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3320 const char *from
, *to
;
3321 } arial_0
, courier_new_0
, times_new_roman_0
;
3322 } nls_update_font_list
[] =
3324 /* Latin 1 (United States) */
3325 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3327 "Tahoma","Times New Roman",
3328 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3331 /* Latin 1 (Multilingual) */
3332 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3333 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3334 "Tahoma","Times New Roman", /* FIXME unverified */
3335 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3338 /* Eastern Europe */
3339 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3340 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3341 "Tahoma","Times New Roman", /* FIXME unverified */
3342 "Fixedsys,238", "System,238",
3343 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3344 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3345 { "Arial CE,0", "Arial,238" },
3346 { "Courier New CE,0", "Courier New,238" },
3347 { "Times New Roman CE,0", "Times New Roman,238" }
3350 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3351 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3352 "Tahoma","Times New Roman", /* FIXME unverified */
3353 "Fixedsys,204", "System,204",
3354 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3355 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3356 { "Arial Cyr,0", "Arial,204" },
3357 { "Courier New Cyr,0", "Courier New,204" },
3358 { "Times New Roman Cyr,0", "Times New Roman,204" }
3361 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3362 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3363 "Tahoma","Times New Roman", /* FIXME unverified */
3364 "Fixedsys,161", "System,161",
3365 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3366 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3367 { "Arial Greek,0", "Arial,161" },
3368 { "Courier New Greek,0", "Courier New,161" },
3369 { "Times New Roman Greek,0", "Times New Roman,161" }
3372 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3373 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3374 "Tahoma","Times New Roman", /* FIXME unverified */
3375 "Fixedsys,162", "System,162",
3376 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3377 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3378 { "Arial Tur,0", "Arial,162" },
3379 { "Courier New Tur,0", "Courier New,162" },
3380 { "Times New Roman Tur,0", "Times New Roman,162" }
3383 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3384 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3385 "Tahoma","Times New Roman", /* FIXME unverified */
3386 "Fixedsys,177", "System,177",
3387 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3388 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3392 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3393 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3394 "Tahoma","Times New Roman", /* FIXME unverified */
3395 "Fixedsys,178", "System,178",
3396 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3397 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3401 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3402 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3403 "Tahoma","Times New Roman", /* FIXME unverified */
3404 "Fixedsys,186", "System,186",
3405 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3406 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3407 { "Arial Baltic,0", "Arial,186" },
3408 { "Courier New Baltic,0", "Courier New,186" },
3409 { "Times New Roman Baltic,0", "Times New Roman,186" }
3412 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3413 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3414 "Tahoma","Times New Roman", /* FIXME unverified */
3415 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3419 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3420 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3421 "Tahoma","Times New Roman", /* FIXME unverified */
3422 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3426 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3427 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3428 "MS UI Gothic","MS Serif",
3429 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3432 /* Chinese Simplified */
3433 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3434 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3435 "SimSun", "NSimSun",
3436 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3440 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3441 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3443 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3446 /* Chinese Traditional */
3447 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3449 "PMingLiU", "MingLiU",
3450 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3455 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3457 return ( ansi_cp
== 932 /* CP932 for Japanese */
3458 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3459 || ansi_cp
== 949 /* CP949 for Korean */
3460 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3463 static inline HKEY
create_fonts_NT_registry_key(void)
3467 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3468 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3472 static inline HKEY
create_fonts_9x_registry_key(void)
3476 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3477 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3481 static inline HKEY
create_config_fonts_registry_key(void)
3485 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3486 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3490 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3492 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3494 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3495 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3496 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3497 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3500 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3503 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3505 RegDeleteValueA(hkey
, name
);
3508 static void update_font_info(void)
3510 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3511 char buf
[40], cpbuf
[40];
3514 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3515 DWORD screen_dpi
= 96, font_dpi
= 0;
3518 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3519 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3520 &hkey
) == ERROR_SUCCESS
)
3522 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3526 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3529 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3531 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3532 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3533 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3534 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3535 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3537 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3538 if (is_dbcs_ansi_cp(ansi_cp
))
3539 use_default_fallback
= TRUE
;
3542 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3544 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3549 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3550 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3552 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3553 ansi_cp
, oem_cp
, screen_dpi
);
3555 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3556 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3559 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3563 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3564 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3566 hkey
= create_config_fonts_registry_key();
3567 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3568 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3569 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3572 hkey
= create_fonts_NT_registry_key();
3573 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3576 hkey
= create_fonts_9x_registry_key();
3577 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3580 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3582 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3583 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3584 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3585 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3587 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3588 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3589 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3590 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3591 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3592 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3593 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3594 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3596 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3597 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3598 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3606 /* Delete the FontSubstitutes from other locales */
3607 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3609 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3610 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3611 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3617 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3620 static BOOL
init_freetype(void)
3622 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3625 "Wine cannot find the FreeType font library. To enable Wine to\n"
3626 "use TrueType fonts please install a version of FreeType greater than\n"
3627 "or equal to 2.0.5.\n"
3628 "http://www.freetype.org\n");
3632 #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;}
3634 LOAD_FUNCPTR(FT_Done_Face
)
3635 LOAD_FUNCPTR(FT_Get_Char_Index
)
3636 LOAD_FUNCPTR(FT_Get_First_Char
)
3637 LOAD_FUNCPTR(FT_Get_Module
)
3638 LOAD_FUNCPTR(FT_Get_Next_Char
)
3639 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3640 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3641 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3642 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3643 LOAD_FUNCPTR(FT_Init_FreeType
)
3644 LOAD_FUNCPTR(FT_Library_Version
)
3645 LOAD_FUNCPTR(FT_Load_Glyph
)
3646 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3647 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3648 #ifndef FT_MULFIX_INLINED
3649 LOAD_FUNCPTR(FT_MulFix
)
3651 LOAD_FUNCPTR(FT_New_Face
)
3652 LOAD_FUNCPTR(FT_New_Memory_Face
)
3653 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3654 LOAD_FUNCPTR(FT_Outline_Transform
)
3655 LOAD_FUNCPTR(FT_Outline_Translate
)
3656 LOAD_FUNCPTR(FT_Render_Glyph
)
3657 LOAD_FUNCPTR(FT_Select_Charmap
)
3658 LOAD_FUNCPTR(FT_Set_Charmap
)
3659 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3660 LOAD_FUNCPTR(FT_Vector_Transform
)
3661 LOAD_FUNCPTR(FT_Vector_Unit
)
3663 /* Don't warn if these ones are missing */
3664 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3665 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3666 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3669 if(pFT_Init_FreeType(&library
) != 0) {
3670 ERR("Can't init FreeType library\n");
3671 wine_dlclose(ft_handle
, NULL
, 0);
3675 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3677 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3678 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3679 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3680 ((FT_Version
.patch
) & 0x0000ff);
3682 font_driver
= &freetype_funcs
;
3687 "Wine cannot find certain functions that it needs inside the FreeType\n"
3688 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3689 "FreeType to at least version 2.1.4.\n"
3690 "http://www.freetype.org\n");
3691 wine_dlclose(ft_handle
, NULL
, 0);
3696 static void init_font_list(void)
3698 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3699 static const WCHAR pathW
[] = {'P','a','t','h',0};
3701 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3702 WCHAR windowsdir
[MAX_PATH
];
3704 const char *data_dir
;
3706 delete_external_font_keys();
3708 /* load the system bitmap fonts */
3709 load_system_fonts();
3711 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3712 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3713 strcatW(windowsdir
, fontsW
);
3714 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3716 ReadFontDir(unixname
, FALSE
);
3717 HeapFree(GetProcessHeap(), 0, unixname
);
3720 /* load the system truetype fonts */
3721 data_dir
= wine_get_data_dir();
3722 if (!data_dir
) data_dir
= wine_get_build_dir();
3723 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3725 strcpy(unixname
, data_dir
);
3726 strcat(unixname
, "/fonts/");
3727 ReadFontDir(unixname
, TRUE
);
3728 HeapFree(GetProcessHeap(), 0, unixname
);
3731 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3732 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3733 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3735 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3736 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3737 &hkey
) == ERROR_SUCCESS
)
3739 LPWSTR data
, valueW
;
3740 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3741 &valuelen
, &datalen
, NULL
, NULL
);
3743 valuelen
++; /* returned value doesn't include room for '\0' */
3744 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3745 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3748 dlen
= datalen
* sizeof(WCHAR
);
3750 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3751 &dlen
) == ERROR_SUCCESS
)
3753 if(data
[0] && (data
[1] == ':'))
3755 if((unixname
= wine_get_unix_file_name(data
)))
3757 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3758 HeapFree(GetProcessHeap(), 0, unixname
);
3761 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3763 WCHAR pathW
[MAX_PATH
];
3764 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3767 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3768 if((unixname
= wine_get_unix_file_name(pathW
)))
3770 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3771 HeapFree(GetProcessHeap(), 0, unixname
);
3774 load_font_from_data_dir(data
);
3776 /* reset dlen and vlen */
3781 HeapFree(GetProcessHeap(), 0, data
);
3782 HeapFree(GetProcessHeap(), 0, valueW
);
3786 #ifdef SONAME_LIBFONTCONFIG
3787 load_fontconfig_fonts();
3788 #elif defined(HAVE_CARBON_CARBON_H)
3792 /* then look in any directories that we've specified in the config file */
3793 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3794 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3800 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3802 len
+= sizeof(WCHAR
);
3803 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3804 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3806 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3807 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3808 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3809 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3814 LPSTR next
= strchr( ptr
, ':' );
3815 if (next
) *next
++ = 0;
3816 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3817 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3819 strcpy( unixname
, home
);
3820 strcat( unixname
, ptr
+ 1 );
3821 ReadFontDir( unixname
, TRUE
);
3822 HeapFree( GetProcessHeap(), 0, unixname
);
3825 ReadFontDir( ptr
, TRUE
);
3828 HeapFree( GetProcessHeap(), 0, valueA
);
3830 HeapFree( GetProcessHeap(), 0, valueW
);
3836 static BOOL
move_to_front(const WCHAR
*name
)
3838 Family
*family
, *cursor2
;
3839 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3841 if(!strcmpiW(family
->FamilyName
, name
))
3843 list_remove(&family
->entry
);
3844 list_add_head(&font_list
, &family
->entry
);
3851 static BOOL
set_default(const WCHAR
**name_list
)
3855 if (move_to_front(*name_list
)) return TRUE
;
3862 static void reorder_font_list(void)
3864 set_default( default_serif_list
);
3865 set_default( default_fixed_list
);
3866 set_default( default_sans_list
);
3869 /*************************************************************
3872 * Initialize FreeType library and create a list of available faces
3874 BOOL
WineEngInit(void)
3879 /* update locale dependent font info in registry */
3882 if(!init_freetype()) return FALSE
;
3884 #ifdef SONAME_LIBFONTCONFIG
3888 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3890 ERR("Failed to create font mutex\n");
3893 WaitForSingleObject(font_mutex
, INFINITE
);
3895 create_font_cache_key(&hkey_font_cache
, &disposition
);
3897 if(disposition
== REG_CREATED_NEW_KEY
)
3900 load_font_list_from_cache(hkey_font_cache
);
3902 reorder_font_list();
3909 if(disposition
== REG_CREATED_NEW_KEY
)
3910 update_reg_entries();
3912 init_system_links();
3914 ReleaseMutex(font_mutex
);
3919 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3922 TT_HoriHeader
*pHori
;
3926 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3927 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3929 if(height
== 0) height
= 16;
3931 /* Calc. height of EM square:
3933 * For +ve lfHeight we have
3934 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3935 * Re-arranging gives:
3936 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3938 * For -ve lfHeight we have
3940 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3941 * with il = winAscent + winDescent - units_per_em]
3946 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3947 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3948 pHori
->Ascender
- pHori
->Descender
);
3950 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3951 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3959 static struct font_mapping
*map_font_file( const char *name
)
3961 struct font_mapping
*mapping
;
3965 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3966 if (fstat( fd
, &st
) == -1) goto error
;
3968 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3970 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3972 mapping
->refcount
++;
3977 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3980 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3983 if (mapping
->data
== MAP_FAILED
)
3985 HeapFree( GetProcessHeap(), 0, mapping
);
3988 mapping
->refcount
= 1;
3989 mapping
->dev
= st
.st_dev
;
3990 mapping
->ino
= st
.st_ino
;
3991 mapping
->size
= st
.st_size
;
3992 list_add_tail( &mappings_list
, &mapping
->entry
);
4000 static void unmap_font_file( struct font_mapping
*mapping
)
4002 if (!--mapping
->refcount
)
4004 list_remove( &mapping
->entry
);
4005 munmap( mapping
->data
, mapping
->size
);
4006 HeapFree( GetProcessHeap(), 0, mapping
);
4010 static LONG
load_VDMX(GdiFont
*, LONG
);
4012 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4019 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4023 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4024 font
->mapping
= map_font_file( filename
);
4025 HeapFree( GetProcessHeap(), 0, filename
);
4028 WARN("failed to map %s\n", debugstr_w(face
->file
));
4031 data_ptr
= font
->mapping
->data
;
4032 data_size
= font
->mapping
->size
;
4036 data_ptr
= face
->font_data_ptr
;
4037 data_size
= face
->font_data_size
;
4040 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4042 ERR("FT_New_Face rets %d\n", err
);
4046 /* set it here, as load_VDMX needs it */
4047 font
->ft_face
= ft_face
;
4049 if(FT_IS_SCALABLE(ft_face
)) {
4050 /* load the VDMX table if we have one */
4051 font
->ppem
= load_VDMX(font
, height
);
4053 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4054 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4056 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4057 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4059 font
->ppem
= height
;
4060 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4061 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4067 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4069 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4070 a single face with the requested charset. The idea is to check if
4071 the selected font supports the current ANSI codepage, if it does
4072 return the corresponding charset, else return the first charset */
4075 int acp
= GetACP(), i
;
4079 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4081 const SYSTEM_LINKS
*font_link
;
4083 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4084 return csi
.ciCharset
;
4086 font_link
= find_font_link(family_name
);
4087 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4088 return csi
.ciCharset
;
4091 for(i
= 0; i
< 32; i
++) {
4093 if(face
->fs
.fsCsb
[0] & fs0
) {
4094 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4096 return csi
.ciCharset
;
4099 FIXME("TCI failing on %x\n", fs0
);
4103 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4104 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4106 return DEFAULT_CHARSET
;
4109 static GdiFont
*alloc_font(void)
4111 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4114 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4115 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4117 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4118 ret
->total_kern_pairs
= (DWORD
)-1;
4119 ret
->kern_pairs
= NULL
;
4120 list_init(&ret
->child_fonts
);
4124 static void free_font(GdiFont
*font
)
4126 CHILD_FONT
*child
, *child_next
;
4129 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4131 list_remove(&child
->entry
);
4133 free_font(child
->font
);
4134 release_face( child
->face
);
4135 HeapFree(GetProcessHeap(), 0, child
);
4138 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4139 if (font
->mapping
) unmap_font_file( font
->mapping
);
4140 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4141 HeapFree(GetProcessHeap(), 0, font
->potm
);
4142 HeapFree(GetProcessHeap(), 0, font
->name
);
4143 for (i
= 0; i
< font
->gmsize
; i
++)
4144 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4145 HeapFree(GetProcessHeap(), 0, font
->gm
);
4146 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4147 HeapFree(GetProcessHeap(), 0, font
);
4151 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4153 FT_Face ft_face
= font
->ft_face
;
4157 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4164 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4166 /* make sure value of len is the value freetype says it needs */
4169 FT_ULong needed
= 0;
4170 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4171 if( !err
&& needed
< len
) len
= needed
;
4173 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4176 TRACE("Can't find table %c%c%c%c\n",
4177 /* bytes were reversed */
4178 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4179 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4185 /*************************************************************
4188 * load the vdmx entry for the specified height
4191 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4192 ( ( (FT_ULong)_x4 << 24 ) | \
4193 ( (FT_ULong)_x3 << 16 ) | \
4194 ( (FT_ULong)_x2 << 8 ) | \
4197 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4212 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4216 BYTE devXRatio
, devYRatio
;
4217 USHORT numRecs
, numRatios
;
4218 DWORD result
, offset
= -1;
4222 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4224 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4227 /* FIXME: need the real device aspect ratio */
4231 numRecs
= GET_BE_WORD(hdr
[1]);
4232 numRatios
= GET_BE_WORD(hdr
[2]);
4234 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4235 for(i
= 0; i
< numRatios
; i
++) {
4238 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4239 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4242 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4244 if((ratio
.xRatio
== 0 &&
4245 ratio
.yStartRatio
== 0 &&
4246 ratio
.yEndRatio
== 0) ||
4247 (devXRatio
== ratio
.xRatio
&&
4248 devYRatio
>= ratio
.yStartRatio
&&
4249 devYRatio
<= ratio
.yEndRatio
))
4251 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4252 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4253 offset
= GET_BE_WORD(tmp
);
4259 FIXME("No suitable ratio found\n");
4263 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4265 BYTE startsz
, endsz
;
4268 recs
= GET_BE_WORD(group
.recs
);
4269 startsz
= group
.startsz
;
4270 endsz
= group
.endsz
;
4272 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4274 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4275 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4276 if(result
== GDI_ERROR
) {
4277 FIXME("Failed to retrieve vTable\n");
4282 for(i
= 0; i
< recs
; i
++) {
4283 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4284 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4285 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4287 if(yMax
+ -yMin
== height
) {
4290 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4293 if(yMax
+ -yMin
> height
) {
4296 goto end
; /* failed */
4298 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4299 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4300 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4301 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4307 TRACE("ppem not found for height %d\n", height
);
4311 HeapFree(GetProcessHeap(), 0, vTable
);
4317 static void dump_gdi_font_list(void)
4321 TRACE("---------- Font Cache ----------\n");
4322 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4323 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4324 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4327 static void grab_font( GdiFont
*font
)
4329 if (!font
->refcount
++)
4331 list_remove( &font
->unused_entry
);
4332 unused_font_count
--;
4336 static void release_font( GdiFont
*font
)
4339 if (!--font
->refcount
)
4341 TRACE( "font %p\n", font
);
4343 /* add it to the unused list */
4344 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4345 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4347 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4348 TRACE( "freeing %p\n", font
);
4349 list_remove( &font
->entry
);
4350 list_remove( &font
->unused_entry
);
4353 else unused_font_count
++;
4355 if (TRACE_ON(font
)) dump_gdi_font_list();
4359 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4361 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4362 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4363 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4364 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4365 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4368 static void calc_hash(FONT_DESC
*pfd
)
4370 DWORD hash
= 0, *ptr
, two_chars
;
4374 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4376 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4378 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4380 pwc
= (WCHAR
*)&two_chars
;
4382 *pwc
= toupperW(*pwc
);
4384 *pwc
= toupperW(*pwc
);
4388 hash
^= !pfd
->can_use_bitmap
;
4393 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4400 fd
.can_use_bitmap
= can_use_bitmap
;
4403 /* try the in-use list */
4404 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4406 if(fontcmp(ret
, &fd
)) continue;
4407 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4408 list_remove( &ret
->entry
);
4409 list_add_head( &gdi_font_list
, &ret
->entry
);
4416 static void add_to_cache(GdiFont
*font
)
4418 static DWORD cache_num
= 1;
4420 font
->cache_num
= cache_num
++;
4421 list_add_head(&gdi_font_list
, &font
->entry
);
4422 TRACE( "font %p\n", font
);
4425 /*************************************************************
4426 * create_child_font_list
4428 static BOOL
create_child_font_list(GdiFont
*font
)
4431 SYSTEM_LINKS
*font_link
;
4432 CHILD_FONT
*font_link_entry
, *new_child
;
4436 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4437 font_name
= psub
? psub
->to
.name
: font
->name
;
4438 font_link
= find_font_link(font_name
);
4439 if (font_link
!= NULL
)
4441 TRACE("found entry in system list\n");
4442 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4444 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4445 new_child
->face
= font_link_entry
->face
;
4446 new_child
->font
= NULL
;
4447 new_child
->face
->refcount
++;
4448 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4449 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4454 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4455 * Sans Serif. This is how asian windows get default fallbacks for fonts
4457 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4458 font
->charset
!= OEM_CHARSET
&&
4459 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4461 font_link
= find_font_link(szDefaultFallbackLink
);
4462 if (font_link
!= NULL
)
4464 TRACE("found entry in default fallback list\n");
4465 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4467 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4468 new_child
->face
= font_link_entry
->face
;
4469 new_child
->font
= NULL
;
4470 new_child
->face
->refcount
++;
4471 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4472 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4481 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4483 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4485 if (pFT_Set_Charmap
)
4488 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4490 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4492 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4494 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4496 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4497 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4499 switch (ft_face
->charmaps
[i
]->platform_id
)
4502 cmap_def
= ft_face
->charmaps
[i
];
4504 case 0: /* Apple Unicode */
4505 cmap0
= ft_face
->charmaps
[i
];
4507 case 1: /* Macintosh */
4508 cmap1
= ft_face
->charmaps
[i
];
4511 cmap2
= ft_face
->charmaps
[i
];
4513 case 3: /* Microsoft */
4514 cmap3
= ft_face
->charmaps
[i
];
4519 if (cmap3
) /* prefer Microsoft cmap table */
4520 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4522 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4524 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4526 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4528 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4530 return ft_err
== FT_Err_Ok
;
4533 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4537 /*************************************************************
4540 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4541 LPCWSTR output
, const DEVMODEW
*devmode
)
4543 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4545 if (!physdev
) return FALSE
;
4546 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4551 /*************************************************************
4554 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4556 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4557 release_font( physdev
->font
);
4558 HeapFree( GetProcessHeap(), 0, physdev
);
4562 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4564 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4565 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4566 const FT_Encoding
*encs
= regular_order
;
4568 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4572 if (select_charmap( face
, *encs
)) break;
4578 #define GASP_GRIDFIT 0x01
4579 #define GASP_DOGRAY 0x02
4580 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4582 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4585 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4586 WORD
*alloced
= NULL
, *ptr
= buf
;
4587 WORD num_recs
, version
;
4591 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4592 if (size
== GDI_ERROR
) return FALSE
;
4593 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4594 if (size
> sizeof(buf
))
4596 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4597 if (!ptr
) return FALSE
;
4600 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4602 version
= GET_BE_WORD( *ptr
++ );
4603 num_recs
= GET_BE_WORD( *ptr
++ );
4605 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4607 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4613 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4614 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4617 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4621 HeapFree( GetProcessHeap(), 0, alloced
);
4625 /*************************************************************
4626 * freetype_SelectFont
4628 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4630 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4632 Face
*face
, *best
, *best_bitmap
;
4633 Family
*family
, *last_resort_family
;
4634 const struct list
*face_list
;
4635 INT height
, width
= 0;
4636 unsigned int score
= 0, new_score
;
4637 signed int diff
= 0, newdiff
;
4638 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4642 FontSubst
*psub
= NULL
;
4643 DC
*dc
= get_dc_ptr( dev
->hdc
);
4644 const SYSTEM_LINKS
*font_link
;
4646 if (!hfont
) /* notification that the font has been changed by another driver */
4648 release_font( physdev
->font
);
4649 physdev
->font
= NULL
;
4650 release_dc_ptr( dc
);
4654 GetObjectW( hfont
, sizeof(lf
), &lf
);
4655 lf
.lfWidth
= abs(lf
.lfWidth
);
4657 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4659 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4660 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4661 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4664 if(dc
->GraphicsMode
== GM_ADVANCED
)
4666 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4667 /* Try to avoid not necessary glyph transformations */
4668 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4670 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4671 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4672 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4677 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4678 font scaling abilities. */
4679 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4680 dcmat
.eM21
= dcmat
.eM12
= 0;
4681 lf
.lfOrientation
= lf
.lfEscapement
;
4682 if (dc
->vport2WorldValid
)
4684 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4685 lf
.lfOrientation
= -lf
.lfOrientation
;
4686 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4687 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4691 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4692 dcmat
.eM21
, dcmat
.eM22
);
4695 EnterCriticalSection( &freetype_cs
);
4697 /* check the cache first */
4698 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4699 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4703 TRACE("not in cache\n");
4706 ret
->font_desc
.matrix
= dcmat
;
4707 ret
->font_desc
.lf
= lf
;
4708 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4709 calc_hash(&ret
->font_desc
);
4711 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4712 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4713 original value lfCharSet. Note this is a special case for
4714 Symbol and doesn't happen at least for "Wingdings*" */
4716 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4717 lf
.lfCharSet
= SYMBOL_CHARSET
;
4719 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4720 switch(lf
.lfCharSet
) {
4721 case DEFAULT_CHARSET
:
4722 csi
.fs
.fsCsb
[0] = 0;
4725 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4726 csi
.fs
.fsCsb
[0] = 0;
4732 if(lf
.lfFaceName
[0] != '\0') {
4733 CHILD_FONT
*font_link_entry
;
4734 LPWSTR FaceName
= lf
.lfFaceName
;
4736 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4739 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4740 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4741 if (psub
->to
.charset
!= -1)
4742 lf
.lfCharSet
= psub
->to
.charset
;
4745 /* We want a match on name and charset or just name if
4746 charset was DEFAULT_CHARSET. If the latter then
4747 we fixup the returned charset later in get_nearest_charset
4748 where we'll either use the charset of the current ansi codepage
4749 or if that's unavailable the first charset that the font supports.
4751 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4752 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4753 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4755 font_link
= find_font_link(family
->FamilyName
);
4756 face_list
= get_face_list_from_family(family
);
4757 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4758 if (!(face
->scalable
|| can_use_bitmap
))
4760 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4762 if (font_link
!= NULL
&&
4763 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4765 if (!csi
.fs
.fsCsb
[0])
4771 /* Search by full face name. */
4772 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4773 face_list
= get_face_list_from_family(family
);
4774 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4775 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4776 (face
->scalable
|| can_use_bitmap
))
4778 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4780 font_link
= find_font_link(family
->FamilyName
);
4781 if (font_link
!= NULL
&&
4782 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4789 * Try check the SystemLink list first for a replacement font.
4790 * We may find good replacements there.
4792 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4794 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4795 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4797 TRACE("found entry in system list\n");
4798 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4800 const SYSTEM_LINKS
*links
;
4802 face
= font_link_entry
->face
;
4803 if (!(face
->scalable
|| can_use_bitmap
))
4805 family
= face
->family
;
4806 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4808 links
= find_font_link(family
->FamilyName
);
4809 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4816 psub
= NULL
; /* substitution is no more relevant */
4818 /* If requested charset was DEFAULT_CHARSET then try using charset
4819 corresponding to the current ansi codepage */
4820 if (!csi
.fs
.fsCsb
[0])
4823 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4824 FIXME("TCI failed on codepage %d\n", acp
);
4825 csi
.fs
.fsCsb
[0] = 0;
4827 lf
.lfCharSet
= csi
.ciCharset
;
4830 want_vertical
= (lf
.lfFaceName
[0] == '@');
4832 /* Face families are in the top 4 bits of lfPitchAndFamily,
4833 so mask with 0xF0 before testing */
4835 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4836 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4837 strcpyW(lf
.lfFaceName
, defFixed
);
4838 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4839 strcpyW(lf
.lfFaceName
, defSerif
);
4840 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4841 strcpyW(lf
.lfFaceName
, defSans
);
4843 strcpyW(lf
.lfFaceName
, defSans
);
4844 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4845 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4846 font_link
= find_font_link(family
->FamilyName
);
4847 face_list
= get_face_list_from_family(family
);
4848 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4849 if (!(face
->scalable
|| can_use_bitmap
))
4851 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4853 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4859 last_resort_family
= NULL
;
4860 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4861 font_link
= find_font_link(family
->FamilyName
);
4862 face_list
= get_face_list_from_family(family
);
4863 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4864 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
4865 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4866 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4869 if(can_use_bitmap
&& !last_resort_family
)
4870 last_resort_family
= family
;
4875 if(last_resort_family
) {
4876 family
= last_resort_family
;
4877 csi
.fs
.fsCsb
[0] = 0;
4881 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4882 face_list
= get_face_list_from_family(family
);
4883 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4884 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
4885 csi
.fs
.fsCsb
[0] = 0;
4886 WARN("just using first face for now\n");
4889 if(can_use_bitmap
&& !last_resort_family
)
4890 last_resort_family
= family
;
4893 if(!last_resort_family
) {
4894 FIXME("can't find a single appropriate font - bailing\n");
4900 WARN("could only find a bitmap font - this will probably look awful!\n");
4901 family
= last_resort_family
;
4902 csi
.fs
.fsCsb
[0] = 0;
4905 it
= lf
.lfItalic
? 1 : 0;
4906 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4908 height
= lf
.lfHeight
;
4910 face
= best
= best_bitmap
= NULL
;
4911 font_link
= find_font_link(family
->FamilyName
);
4912 face_list
= get_face_list_from_family(family
);
4913 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4915 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4916 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4921 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4922 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4923 new_score
= (italic
^ it
) + (bold
^ bd
);
4924 if(!best
|| new_score
<= score
)
4926 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4927 italic
, bold
, it
, bd
);
4930 if(best
->scalable
&& score
== 0) break;
4934 newdiff
= height
- (signed int)(best
->size
.height
);
4936 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4937 if(!best_bitmap
|| new_score
< score
||
4938 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4940 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4943 if(score
== 0 && diff
== 0) break;
4950 face
= best
->scalable
? best
: best_bitmap
;
4951 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4952 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4955 height
= lf
.lfHeight
;
4959 if(csi
.fs
.fsCsb
[0]) {
4960 ret
->charset
= lf
.lfCharSet
;
4961 ret
->codepage
= csi
.ciACP
;
4964 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4966 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4967 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
4969 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4971 if(!face
->scalable
) {
4972 /* Windows uses integer scaling factors for bitmap fonts */
4973 INT scale
, scaled_height
;
4974 GdiFont
*cachedfont
;
4976 /* FIXME: rotation of bitmap fonts is ignored */
4977 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4979 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4980 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4981 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4982 /* As we changed the matrix, we need to search the cache for the font again,
4983 * otherwise we might explode the cache. */
4984 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4985 TRACE("Found cached font after non-scalable matrix rescale!\n");
4990 calc_hash(&ret
->font_desc
);
4992 if (height
!= 0) height
= diff
;
4993 height
+= face
->size
.height
;
4995 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4996 scaled_height
= scale
* face
->size
.height
;
4997 /* Only jump to the next height if the difference <= 25% original height */
4998 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4999 /* The jump between unscaled and doubled is delayed by 1 */
5000 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5001 ret
->scale_y
= scale
;
5003 width
= face
->size
.x_ppem
>> 6;
5004 height
= face
->size
.y_ppem
>> 6;
5008 TRACE("font scale y: %f\n", ret
->scale_y
);
5010 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5019 ret
->ntmFlags
= face
->ntmFlags
;
5021 pick_charmap( ret
->ft_face
, ret
->charset
);
5023 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5024 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5025 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5026 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5027 create_child_font_list(ret
);
5029 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5031 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5032 if (length
!= GDI_ERROR
)
5034 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5035 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5036 TRACE("Loaded GSUB table of %i bytes\n",length
);
5039 ret
->aa_flags
= HIWORD( face
->flags
);
5041 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5047 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5049 switch (lf
.lfQuality
)
5051 case NONANTIALIASED_QUALITY
:
5052 case ANTIALIASED_QUALITY
:
5053 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5055 case CLEARTYPE_QUALITY
:
5056 case CLEARTYPE_NATURAL_QUALITY
:
5058 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5059 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5061 /* fixup the antialiasing flags for that font */
5064 case WINE_GGO_HRGB_BITMAP
:
5065 case WINE_GGO_HBGR_BITMAP
:
5066 case WINE_GGO_VRGB_BITMAP
:
5067 case WINE_GGO_VBGR_BITMAP
:
5068 if (is_subpixel_rendering_enabled()) break;
5069 *aa_flags
= GGO_GRAY4_BITMAP
;
5071 case GGO_GRAY2_BITMAP
:
5072 case GGO_GRAY4_BITMAP
:
5073 case GGO_GRAY8_BITMAP
:
5074 case WINE_GGO_GRAY16_BITMAP
:
5075 if (is_hinting_enabled())
5078 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5080 TRACE( "font %s %d aa disabled by GASP\n",
5081 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5082 *aa_flags
= GGO_BITMAP
;
5087 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5088 release_font( physdev
->font
);
5089 physdev
->font
= ret
;
5091 LeaveCriticalSection( &freetype_cs
);
5092 release_dc_ptr( dc
);
5093 return ret
? hfont
: 0;
5096 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5103 id
+= IDS_FIRST_SCRIPT
;
5104 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5105 if (!rsrc
) return 0;
5106 hMem
= LoadResource( gdi32_module
, rsrc
);
5107 if (!hMem
) return 0;
5109 p
= LockResource( hMem
);
5111 while (id
--) p
+= *p
+ 1;
5113 i
= min(LF_FACESIZE
- 1, *p
);
5114 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5120 /***************************************************
5121 * create_enum_charset_list
5123 * This function creates charset enumeration list because in DEFAULT_CHARSET
5124 * case, the ANSI codepage's charset takes precedence over other charsets.
5125 * This function works as a filter other than DEFAULT_CHARSET case.
5127 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5132 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5133 csi
.fs
.fsCsb
[0] != 0) {
5134 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5135 list
->element
[n
].charset
= csi
.ciCharset
;
5136 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5139 else { /* charset is DEFAULT_CHARSET or invalid. */
5143 /* Set the current codepage's charset as the first element. */
5145 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5146 csi
.fs
.fsCsb
[0] != 0) {
5147 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5148 list
->element
[n
].charset
= csi
.ciCharset
;
5149 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5150 mask
|= csi
.fs
.fsCsb
[0];
5154 /* Fill out left elements. */
5155 for (i
= 0; i
< 32; i
++) {
5157 fs
.fsCsb
[0] = 1L << i
;
5159 if (fs
.fsCsb
[0] & mask
)
5160 continue; /* skip, already added. */
5161 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5162 continue; /* skip, this is an invalid fsCsb bit. */
5164 list
->element
[n
].mask
= fs
.fsCsb
[0];
5165 list
->element
[n
].charset
= csi
.ciCharset
;
5166 load_script_name( i
, list
->element
[n
].name
);
5167 mask
|= fs
.fsCsb
[0];
5171 /* add catch all mask for remaining bits */
5174 list
->element
[n
].mask
= ~mask
;
5175 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5176 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5185 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5186 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5191 if (face
->cached_enum_data
)
5194 *pelf
= face
->cached_enum_data
->elf
;
5195 *pntm
= face
->cached_enum_data
->ntm
;
5196 *ptype
= face
->cached_enum_data
->type
;
5200 font
= alloc_font();
5202 if(face
->scalable
) {
5206 height
= face
->size
.y_ppem
>> 6;
5207 width
= face
->size
.x_ppem
>> 6;
5209 font
->scale_y
= 1.0;
5211 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5217 font
->name
= strdupW( family_name
);
5218 font
->ntmFlags
= face
->ntmFlags
;
5220 if (get_outline_text_metrics(font
))
5222 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5224 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5225 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5226 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5228 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5229 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5231 lstrcpynW(pelf
->elfFullName
,
5232 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5234 lstrcpynW(pelf
->elfStyle
,
5235 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5240 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5242 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5243 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5244 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5246 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5248 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5250 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5251 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5254 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5255 pntm
->ntmFontSig
= face
->fs
;
5257 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5259 pelf
->elfLogFont
.lfEscapement
= 0;
5260 pelf
->elfLogFont
.lfOrientation
= 0;
5261 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5262 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5263 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5264 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5265 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5266 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5267 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5268 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5269 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5270 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5271 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5274 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5275 *ptype
|= TRUETYPE_FONTTYPE
;
5276 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5277 *ptype
|= DEVICE_FONTTYPE
;
5278 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5279 *ptype
|= RASTER_FONTTYPE
;
5281 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5282 if (face
->cached_enum_data
)
5284 face
->cached_enum_data
->elf
= *pelf
;
5285 face
->cached_enum_data
->ntm
= *pntm
;
5286 face
->cached_enum_data
->type
= *ptype
;
5292 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5295 const struct list
*face_list
;
5297 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5299 face_list
= get_face_list_from_family(family
);
5300 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5301 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5306 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5308 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5310 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5313 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5314 FONTENUMPROCW proc
, LPARAM lparam
)
5317 NEWTEXTMETRICEXW ntm
;
5321 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5322 for(i
= 0; i
< list
->total
; i
++) {
5323 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5324 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5325 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5326 i
= list
->total
; /* break out of loop after enumeration */
5330 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5331 /* use the DEFAULT_CHARSET case only if no other charset is present */
5332 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5333 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5334 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5335 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5336 if (!elf
.elfScript
[0])
5337 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5339 /* Font Replacement */
5340 if (family
!= face
->family
)
5342 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5344 strcpyW(elf
.elfFullName
, face
->FullName
);
5346 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5348 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5349 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5350 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5351 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5352 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5353 ntm
.ntmTm
.ntmFlags
);
5354 /* release section before callback (FIXME) */
5355 LeaveCriticalSection( &freetype_cs
);
5356 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5357 EnterCriticalSection( &freetype_cs
);
5362 /*************************************************************
5363 * freetype_EnumFonts
5365 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5369 const struct list
*face_list
;
5371 struct enum_charset_list enum_charsets
;
5375 lf
.lfCharSet
= DEFAULT_CHARSET
;
5376 lf
.lfPitchAndFamily
= 0;
5377 lf
.lfFaceName
[0] = 0;
5381 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5383 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5386 EnterCriticalSection( &freetype_cs
);
5387 if(plf
->lfFaceName
[0]) {
5389 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5392 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5393 debugstr_w(psub
->to
.name
));
5395 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5399 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5400 if (!family_matches(family
, plf
)) continue;
5401 face_list
= get_face_list_from_family(family
);
5402 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5403 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5404 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5408 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5409 face_list
= get_face_list_from_family(family
);
5410 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5411 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5414 LeaveCriticalSection( &freetype_cs
);
5418 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5420 pt
->x
.value
= vec
->x
>> 6;
5421 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5422 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5423 pt
->y
.value
= vec
->y
>> 6;
5424 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5425 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5429 /***************************************************
5430 * According to the MSDN documentation on WideCharToMultiByte,
5431 * certain codepages cannot set the default_used parameter.
5432 * This returns TRUE if the codepage can set that parameter, false else
5433 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5435 static BOOL
codepage_sets_default_used(UINT codepage
)
5449 * GSUB Table handling functions
5452 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5454 const GSUB_CoverageFormat1
* cf1
;
5458 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5460 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5462 TRACE("Coverage Format 1, %i glyphs\n",count
);
5463 for (i
= 0; i
< count
; i
++)
5464 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5468 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5470 const GSUB_CoverageFormat2
* cf2
;
5473 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5475 count
= GET_BE_WORD(cf2
->RangeCount
);
5476 TRACE("Coverage Format 2, %i ranges\n",count
);
5477 for (i
= 0; i
< count
; i
++)
5479 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5481 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5482 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5484 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5485 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5491 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5496 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5498 const GSUB_ScriptList
*script
;
5499 const GSUB_Script
*deflt
= NULL
;
5501 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5503 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5504 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5506 const GSUB_Script
*scr
;
5509 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5510 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5512 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5514 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5520 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5524 const GSUB_LangSys
*Lang
;
5526 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5528 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5530 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5531 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5533 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5536 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5539 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5545 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5548 const GSUB_FeatureList
*feature
;
5549 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5551 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5552 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5554 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5555 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5557 const GSUB_Feature
*feat
;
5558 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5565 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5569 const GSUB_LookupList
*lookup
;
5570 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5572 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5573 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5575 const GSUB_LookupTable
*look
;
5576 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5577 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5578 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5579 if (GET_BE_WORD(look
->LookupType
) != 1)
5580 FIXME("We only handle SubType 1\n");
5585 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5587 const GSUB_SingleSubstFormat1
*ssf1
;
5588 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5589 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5590 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5592 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5593 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5594 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5596 TRACE(" Glyph 0x%x ->",glyph
);
5597 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5598 TRACE(" 0x%x\n",glyph
);
5603 const GSUB_SingleSubstFormat2
*ssf2
;
5607 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5608 offset
= GET_BE_WORD(ssf1
->Coverage
);
5609 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5610 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5611 TRACE(" Coverage index %i\n",index
);
5614 TRACE(" Glyph is 0x%x ->",glyph
);
5615 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5616 TRACE("0x%x\n",glyph
);
5625 static const char* get_opentype_script(const GdiFont
*font
)
5628 * I am not sure if this is the correct way to generate our script tag
5631 switch (font
->charset
)
5633 case ANSI_CHARSET
: return "latn";
5634 case BALTIC_CHARSET
: return "latn"; /* ?? */
5635 case CHINESEBIG5_CHARSET
: return "hani";
5636 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5637 case GB2312_CHARSET
: return "hani";
5638 case GREEK_CHARSET
: return "grek";
5639 case HANGUL_CHARSET
: return "hang";
5640 case RUSSIAN_CHARSET
: return "cyrl";
5641 case SHIFTJIS_CHARSET
: return "kana";
5642 case TURKISH_CHARSET
: return "latn"; /* ?? */
5643 case VIETNAMESE_CHARSET
: return "latn";
5644 case JOHAB_CHARSET
: return "latn"; /* ?? */
5645 case ARABIC_CHARSET
: return "arab";
5646 case HEBREW_CHARSET
: return "hebr";
5647 case THAI_CHARSET
: return "thai";
5648 default: return "latn";
5652 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5654 const GSUB_Header
*header
;
5655 const GSUB_Script
*script
;
5656 const GSUB_LangSys
*language
;
5657 const GSUB_Feature
*feature
;
5659 if (!font
->GSUB_Table
)
5662 header
= font
->GSUB_Table
;
5664 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5667 TRACE("Script not found\n");
5670 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5673 TRACE("Language not found\n");
5676 feature
= GSUB_get_feature(header
, language
, "vrt2");
5678 feature
= GSUB_get_feature(header
, language
, "vert");
5681 TRACE("vrt2/vert feature not found\n");
5684 return GSUB_apply_feature(header
, feature
, glyph
);
5687 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5691 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5692 WCHAR wc
= (WCHAR
)glyph
;
5694 BOOL
*default_used_pointer
;
5697 default_used_pointer
= NULL
;
5698 default_used
= FALSE
;
5699 if (codepage_sets_default_used(font
->codepage
))
5700 default_used_pointer
= &default_used
;
5701 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5703 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
5704 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
5709 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5710 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5714 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5716 if (glyph
< 0x100) glyph
+= 0xf000;
5717 /* there is a number of old pre-Unicode "broken" TTFs, which
5718 do have symbols at U+00XX instead of U+f0XX */
5719 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5720 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5722 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5727 /*************************************************************
5728 * freetype_GetGlyphIndices
5730 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5732 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5735 BOOL got_default
= FALSE
;
5739 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5740 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5743 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5745 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5750 EnterCriticalSection( &freetype_cs
);
5752 for(i
= 0; i
< count
; i
++)
5754 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5759 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5761 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5762 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5767 get_text_metrics(physdev
->font
, &textm
);
5768 default_char
= textm
.tmDefaultChar
;
5772 pgi
[i
] = default_char
;
5775 LeaveCriticalSection( &freetype_cs
);
5779 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5781 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5782 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5785 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5787 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5788 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5791 static inline BYTE
get_max_level( UINT format
)
5795 case GGO_GRAY2_BITMAP
: return 4;
5796 case GGO_GRAY4_BITMAP
: return 16;
5797 case GGO_GRAY8_BITMAP
: return 64;
5802 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5804 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5805 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
5808 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5809 FT_Face ft_face
= incoming_font
->ft_face
;
5810 GdiFont
*font
= incoming_font
;
5811 FT_UInt glyph_index
;
5812 DWORD width
, height
, pitch
, needed
= 0;
5813 FT_Bitmap ft_bitmap
;
5815 INT left
, right
, top
= 0, bottom
= 0, adv
;
5817 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5818 double widthRatio
= 1.0;
5819 FT_Matrix transMat
= identityMat
;
5820 FT_Matrix transMatUnrotated
;
5821 BOOL needsTransform
= FALSE
;
5822 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5823 UINT original_index
;
5824 FT_Fixed avgAdvance
= 0;
5826 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5827 buflen
, buf
, lpmat
);
5829 TRACE("font transform %f %f %f %f\n",
5830 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5831 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5833 if(format
& GGO_GLYPH_INDEX
) {
5834 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5835 original_index
= glyph
;
5836 format
&= ~GGO_GLYPH_INDEX
;
5838 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5839 ft_face
= font
->ft_face
;
5840 original_index
= glyph_index
;
5843 if(format
& GGO_UNHINTED
) {
5844 load_flags
|= FT_LOAD_NO_HINTING
;
5845 format
&= ~GGO_UNHINTED
;
5848 /* tategaki never appears to happen to lower glyph index */
5849 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5852 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5853 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5854 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5855 font
->gmsize
* sizeof(GM
*));
5857 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5858 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5860 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5861 *abc
= FONT_GM(font
,original_index
)->abc
;
5862 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5863 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5864 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5865 return 1; /* FIXME */
5869 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5870 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5872 /* Scaling factor */
5877 get_text_metrics(font
, &tm
);
5879 widthRatio
= (double)font
->aveWidth
;
5880 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5883 widthRatio
= font
->scale_y
;
5885 /* Scaling transform */
5886 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5889 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5892 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5894 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5895 needsTransform
= TRUE
;
5898 /* Slant transform */
5899 if (font
->fake_italic
) {
5902 slantMat
.xx
= (1 << 16);
5903 slantMat
.xy
= ((1 << 16) >> 2);
5905 slantMat
.yy
= (1 << 16);
5906 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5907 needsTransform
= TRUE
;
5910 /* Rotation transform */
5911 transMatUnrotated
= transMat
;
5912 if(font
->orientation
&& !tategaki
) {
5913 FT_Matrix rotationMat
;
5915 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5916 pFT_Vector_Unit(&vecAngle
, angle
);
5917 rotationMat
.xx
= vecAngle
.x
;
5918 rotationMat
.xy
= -vecAngle
.y
;
5919 rotationMat
.yx
= -rotationMat
.xy
;
5920 rotationMat
.yy
= rotationMat
.xx
;
5922 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5923 needsTransform
= TRUE
;
5926 /* World transform */
5927 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5930 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5931 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5932 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5933 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5934 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5935 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5936 needsTransform
= TRUE
;
5939 /* Extra transformation specified by caller */
5940 if (!is_identity_MAT2(lpmat
))
5943 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5944 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
5945 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
5946 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5947 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5948 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5949 needsTransform
= TRUE
;
5952 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
5954 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5957 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5961 if(FT_IS_SCALABLE(incoming_font
->ft_face
)) {
5963 if (get_text_metrics(incoming_font
, &tm
) &&
5964 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
5965 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
,
5966 incoming_font
->ft_face
->size
->metrics
.x_scale
);
5967 if (avgAdvance
&& (ft_face
->glyph
->metrics
.horiAdvance
+63) >> 6 == (avgAdvance
*2+63) >> 6)
5968 TRACE("Fixed-pitch full-width character detected\n");
5970 avgAdvance
= 0; /* cancel this feature */
5974 if(!needsTransform
) {
5975 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5976 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5978 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5980 adv
= (INT
)((avgAdvance
+ 32) >> 6) * 2;
5982 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5983 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5984 ft_face
->glyph
->metrics
.height
) & -64;
5985 lpgm
->gmCellIncX
= adv
;
5986 lpgm
->gmCellIncY
= 0;
5993 for(xc
= 0; xc
< 2; xc
++) {
5994 for(yc
= 0; yc
< 2; yc
++) {
5995 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5996 xc
* ft_face
->glyph
->metrics
.width
);
5997 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5998 yc
* ft_face
->glyph
->metrics
.height
;
5999 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6000 pFT_Vector_Transform(&vec
, &transMat
);
6001 if(xc
== 0 && yc
== 0) {
6002 left
= right
= vec
.x
;
6003 top
= bottom
= vec
.y
;
6005 if(vec
.x
< left
) left
= vec
.x
;
6006 else if(vec
.x
> right
) right
= vec
.x
;
6007 if(vec
.y
< bottom
) bottom
= vec
.y
;
6008 else if(vec
.y
> top
) top
= vec
.y
;
6013 right
= (right
+ 63) & -64;
6014 bottom
= bottom
& -64;
6015 top
= (top
+ 63) & -64;
6017 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6018 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
6020 pFT_Vector_Transform(&vec
, &transMat
);
6021 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6022 if (!avgAdvance
|| vec
.y
)
6023 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6027 pFT_Vector_Transform(&vec
, &transMat
);
6028 lpgm
->gmCellIncX
= ((vec
.x
+32) >> 6) * 2;
6031 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
6033 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6034 if (!avgAdvance
|| vec
.y
)
6035 adv
= (vec
.x
+63) >> 6;
6039 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6040 adv
= ((vec
.x
+32) >> 6) * 2;
6044 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6045 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6046 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
6047 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
6048 abc
->abcA
= left
>> 6;
6049 abc
->abcB
= (right
- left
) >> 6;
6050 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6052 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6053 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6054 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6056 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6057 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6059 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6060 FONT_GM(font
,original_index
)->abc
= *abc
;
6061 FONT_GM(font
,original_index
)->init
= TRUE
;
6064 if(format
== GGO_METRICS
)
6066 return 1; /* FIXME */
6069 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6070 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6072 TRACE("loaded a bitmap\n");
6078 width
= lpgm
->gmBlackBoxX
;
6079 height
= lpgm
->gmBlackBoxY
;
6080 pitch
= ((width
+ 31) >> 5) << 2;
6081 needed
= pitch
* height
;
6083 if(!buf
|| !buflen
) break;
6085 switch(ft_face
->glyph
->format
) {
6086 case ft_glyph_format_bitmap
:
6088 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6089 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
6090 INT h
= ft_face
->glyph
->bitmap
.rows
;
6092 memcpy(dst
, src
, w
);
6093 src
+= ft_face
->glyph
->bitmap
.pitch
;
6099 case ft_glyph_format_outline
:
6100 ft_bitmap
.width
= width
;
6101 ft_bitmap
.rows
= height
;
6102 ft_bitmap
.pitch
= pitch
;
6103 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6104 ft_bitmap
.buffer
= buf
;
6107 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6109 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6111 /* Note: FreeType will only set 'black' bits for us. */
6112 memset(buf
, 0, needed
);
6113 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6117 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6122 case GGO_GRAY2_BITMAP
:
6123 case GGO_GRAY4_BITMAP
:
6124 case GGO_GRAY8_BITMAP
:
6125 case WINE_GGO_GRAY16_BITMAP
:
6127 unsigned int max_level
, row
, col
;
6130 width
= lpgm
->gmBlackBoxX
;
6131 height
= lpgm
->gmBlackBoxY
;
6132 pitch
= (width
+ 3) / 4 * 4;
6133 needed
= pitch
* height
;
6135 if(!buf
|| !buflen
) break;
6137 max_level
= get_max_level( format
);
6139 switch(ft_face
->glyph
->format
) {
6140 case ft_glyph_format_bitmap
:
6142 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6143 INT h
= ft_face
->glyph
->bitmap
.rows
;
6145 memset( buf
, 0, needed
);
6147 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6148 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6149 src
+= ft_face
->glyph
->bitmap
.pitch
;
6154 case ft_glyph_format_outline
:
6156 ft_bitmap
.width
= width
;
6157 ft_bitmap
.rows
= height
;
6158 ft_bitmap
.pitch
= pitch
;
6159 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6160 ft_bitmap
.buffer
= buf
;
6163 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6165 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6167 memset(ft_bitmap
.buffer
, 0, buflen
);
6169 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6171 if (max_level
!= 255)
6173 for (row
= 0, start
= buf
; row
< height
; row
++)
6175 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6176 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6184 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6190 case WINE_GGO_HRGB_BITMAP
:
6191 case WINE_GGO_HBGR_BITMAP
:
6192 case WINE_GGO_VRGB_BITMAP
:
6193 case WINE_GGO_VBGR_BITMAP
:
6194 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6196 switch (ft_face
->glyph
->format
)
6198 case FT_GLYPH_FORMAT_BITMAP
:
6203 width
= lpgm
->gmBlackBoxX
;
6204 height
= lpgm
->gmBlackBoxY
;
6206 needed
= pitch
* height
;
6208 if (!buf
|| !buflen
) break;
6210 memset(buf
, 0, buflen
);
6212 src
= ft_face
->glyph
->bitmap
.buffer
;
6213 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6215 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6218 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6220 if ( src
[x
/ 8] & masks
[x
% 8] )
6221 ((unsigned int *)dst
)[x
] = ~0u;
6230 case FT_GLYPH_FORMAT_OUTLINE
:
6234 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6235 INT x_shift
, y_shift
;
6237 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6238 FT_Render_Mode render_mode
=
6239 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6240 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6242 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6244 if ( render_mode
== FT_RENDER_MODE_LCD
)
6246 lpgm
->gmBlackBoxX
+= 2;
6247 lpgm
->gmptGlyphOrigin
.x
-= 1;
6251 lpgm
->gmBlackBoxY
+= 2;
6252 lpgm
->gmptGlyphOrigin
.y
+= 1;
6256 width
= lpgm
->gmBlackBoxX
;
6257 height
= lpgm
->gmBlackBoxY
;
6259 needed
= pitch
* height
;
6261 if (!buf
|| !buflen
) break;
6263 memset(buf
, 0, buflen
);
6265 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6267 if ( needsTransform
)
6268 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6270 if ( pFT_Library_SetLcdFilter
)
6271 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6272 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6274 src
= ft_face
->glyph
->bitmap
.buffer
;
6275 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6276 src_width
= ft_face
->glyph
->bitmap
.width
;
6277 src_height
= ft_face
->glyph
->bitmap
.rows
;
6279 if ( render_mode
== FT_RENDER_MODE_LCD
)
6287 rgb_interval
= src_pitch
;
6292 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6293 if ( x_shift
< 0 ) x_shift
= 0;
6294 if ( x_shift
+ (src_width
/ hmul
) > width
)
6295 x_shift
= width
- (src_width
/ hmul
);
6297 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6298 if ( y_shift
< 0 ) y_shift
= 0;
6299 if ( y_shift
+ (src_height
/ vmul
) > height
)
6300 y_shift
= height
- (src_height
/ vmul
);
6302 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
6303 while ( src_height
)
6305 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
6309 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6310 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6311 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6312 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6316 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6317 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6318 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6319 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6322 src
+= src_pitch
* vmul
;
6331 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6343 int contour
, point
= 0, first_pt
;
6344 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6345 TTPOLYGONHEADER
*pph
;
6347 DWORD pph_start
, cpfx
, type
;
6349 if(buflen
== 0) buf
= NULL
;
6351 if (needsTransform
&& buf
) {
6352 pFT_Outline_Transform(outline
, &transMat
);
6355 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6356 /* Ignore contours containing one point */
6357 if(point
== outline
->contours
[contour
]) {
6363 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6366 pph
->dwType
= TT_POLYGON_TYPE
;
6367 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6369 needed
+= sizeof(*pph
);
6371 while(point
<= outline
->contours
[contour
]) {
6372 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6373 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6374 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6378 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6381 } while(point
<= outline
->contours
[contour
] &&
6382 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6383 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6384 /* At the end of a contour Windows adds the start point, but
6386 if(point
> outline
->contours
[contour
] &&
6387 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6389 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6391 } else if(point
<= outline
->contours
[contour
] &&
6392 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6393 /* add closing pt for bezier */
6395 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6403 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6406 pph
->cb
= needed
- pph_start
;
6412 /* Convert the quadratic Beziers to cubic Beziers.
6413 The parametric eqn for a cubic Bezier is, from PLRM:
6414 r(t) = at^3 + bt^2 + ct + r0
6415 with the control points:
6420 A quadratic Bezier has the form:
6421 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6423 So equating powers of t leads to:
6424 r1 = 2/3 p1 + 1/3 p0
6425 r2 = 2/3 p1 + 1/3 p2
6426 and of course r0 = p0, r3 = p2
6429 int contour
, point
= 0, first_pt
;
6430 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6431 TTPOLYGONHEADER
*pph
;
6433 DWORD pph_start
, cpfx
, type
;
6434 FT_Vector cubic_control
[4];
6435 if(buflen
== 0) buf
= NULL
;
6437 if (needsTransform
&& buf
) {
6438 pFT_Outline_Transform(outline
, &transMat
);
6441 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6443 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6446 pph
->dwType
= TT_POLYGON_TYPE
;
6447 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6449 needed
+= sizeof(*pph
);
6451 while(point
<= outline
->contours
[contour
]) {
6452 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6453 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6454 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6457 if(type
== TT_PRIM_LINE
) {
6459 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6463 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6466 /* FIXME: Possible optimization in endpoint calculation
6467 if there are two consecutive curves */
6468 cubic_control
[0] = outline
->points
[point
-1];
6469 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6470 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6471 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6472 cubic_control
[0].x
>>= 1;
6473 cubic_control
[0].y
>>= 1;
6475 if(point
+1 > outline
->contours
[contour
])
6476 cubic_control
[3] = outline
->points
[first_pt
];
6478 cubic_control
[3] = outline
->points
[point
+1];
6479 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6480 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6481 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6482 cubic_control
[3].x
>>= 1;
6483 cubic_control
[3].y
>>= 1;
6486 /* r1 = 1/3 p0 + 2/3 p1
6487 r2 = 1/3 p2 + 2/3 p1 */
6488 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6489 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6490 cubic_control
[2] = cubic_control
[1];
6491 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6492 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6493 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6494 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6496 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6497 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6498 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6503 } while(point
<= outline
->contours
[contour
] &&
6504 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6505 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6506 /* At the end of a contour Windows adds the start point,
6507 but only for Beziers and we've already done that.
6509 if(point
<= outline
->contours
[contour
] &&
6510 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6511 /* This is the closing pt of a bezier, but we've already
6512 added it, so just inc point and carry on */
6519 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6522 pph
->cb
= needed
- pph_start
;
6528 FIXME("Unsupported format %d\n", format
);
6534 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6536 FT_Face ft_face
= font
->ft_face
;
6537 FT_WinFNT_HeaderRec winfnt_header
;
6538 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6539 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6540 font
->potm
->otmSize
= size
;
6542 #define TM font->potm->otmTextMetrics
6543 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6545 TM
.tmHeight
= winfnt_header
.pixel_height
;
6546 TM
.tmAscent
= winfnt_header
.ascent
;
6547 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6548 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6549 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6550 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6551 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6552 TM
.tmWeight
= winfnt_header
.weight
;
6554 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6555 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6556 TM
.tmFirstChar
= winfnt_header
.first_char
;
6557 TM
.tmLastChar
= winfnt_header
.last_char
;
6558 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6559 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6560 TM
.tmItalic
= winfnt_header
.italic
;
6561 TM
.tmUnderlined
= font
->underline
;
6562 TM
.tmStruckOut
= font
->strikeout
;
6563 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6564 TM
.tmCharSet
= winfnt_header
.charset
;
6568 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6569 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6570 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6571 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6572 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6573 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6574 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6575 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6577 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6578 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6580 TM
.tmLastChar
= 255;
6581 TM
.tmDefaultChar
= 32;
6582 TM
.tmBreakChar
= 32;
6583 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6584 TM
.tmUnderlined
= font
->underline
;
6585 TM
.tmStruckOut
= font
->strikeout
;
6586 /* NB inverted meaning of TMPF_FIXED_PITCH */
6587 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6588 TM
.tmCharSet
= font
->charset
;
6596 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6598 double scale_x
, scale_y
;
6602 scale_x
= (double)font
->aveWidth
;
6603 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6606 scale_x
= font
->scale_y
;
6608 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6609 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6611 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6612 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6614 SCALE_Y(ptm
->tmHeight
);
6615 SCALE_Y(ptm
->tmAscent
);
6616 SCALE_Y(ptm
->tmDescent
);
6617 SCALE_Y(ptm
->tmInternalLeading
);
6618 SCALE_Y(ptm
->tmExternalLeading
);
6619 SCALE_Y(ptm
->tmOverhang
);
6621 SCALE_X(ptm
->tmAveCharWidth
);
6622 SCALE_X(ptm
->tmMaxCharWidth
);
6628 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6630 double scale_x
, scale_y
;
6634 scale_x
= (double)font
->aveWidth
;
6635 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6638 scale_x
= font
->scale_y
;
6640 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6641 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6643 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6645 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6646 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6648 SCALE_Y(potm
->otmAscent
);
6649 SCALE_Y(potm
->otmDescent
);
6650 SCALE_Y(potm
->otmLineGap
);
6651 SCALE_Y(potm
->otmsCapEmHeight
);
6652 SCALE_Y(potm
->otmsXHeight
);
6653 SCALE_Y(potm
->otmrcFontBox
.top
);
6654 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6655 SCALE_X(potm
->otmrcFontBox
.left
);
6656 SCALE_X(potm
->otmrcFontBox
.right
);
6657 SCALE_Y(potm
->otmMacAscent
);
6658 SCALE_Y(potm
->otmMacDescent
);
6659 SCALE_Y(potm
->otmMacLineGap
);
6660 SCALE_X(potm
->otmptSubscriptSize
.x
);
6661 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6662 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6663 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6664 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6665 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6666 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6667 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6668 SCALE_Y(potm
->otmsStrikeoutSize
);
6669 SCALE_Y(potm
->otmsStrikeoutPosition
);
6670 SCALE_Y(potm
->otmsUnderscoreSize
);
6671 SCALE_Y(potm
->otmsUnderscorePosition
);
6677 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6681 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6683 /* Make sure that the font has sane width/height ratio */
6686 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6688 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6693 *ptm
= font
->potm
->otmTextMetrics
;
6694 scale_font_metrics(font
, ptm
);
6698 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6702 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6704 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6710 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6713 FT_Face ft_face
= font
->ft_face
;
6714 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
6716 TT_HoriHeader
*pHori
;
6717 TT_Postscript
*pPost
;
6718 FT_Fixed x_scale
, y_scale
;
6719 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
6721 INT ascent
, descent
;
6723 TRACE("font=%p\n", font
);
6725 if(!FT_IS_SCALABLE(ft_face
))
6728 needed
= sizeof(*font
->potm
);
6730 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6731 family_nameW
= strdupW(font
->name
);
6733 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
6735 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6738 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6739 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
6741 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
6743 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
6745 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6748 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6749 face_nameW
= strdupW(font
->name
);
6751 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
6752 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
6754 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
6756 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6759 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
6760 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6761 full_nameW
= strdupW(fake_nameW
);
6763 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
6765 /* These names should be read from the TT name table */
6767 /* length of otmpFamilyName */
6770 /* length of otmpFaceName */
6773 /* length of otmpStyleName */
6776 /* length of otmpFullName */
6780 x_scale
= ft_face
->size
->metrics
.x_scale
;
6781 y_scale
= ft_face
->size
->metrics
.y_scale
;
6783 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6785 FIXME("Can't find OS/2 table - not TT font?\n");
6789 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6791 FIXME("Can't find HHEA table - not TT font?\n");
6795 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6797 TRACE("OS/2 winA = %d winD = %d 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",
6798 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6799 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6800 pOS2
->xAvgCharWidth
,
6801 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6802 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6803 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6805 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6806 font
->potm
->otmSize
= needed
;
6808 #define TM font->potm->otmTextMetrics
6810 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6811 ascent
= pHori
->Ascender
;
6812 descent
= -pHori
->Descender
;
6814 ascent
= pOS2
->usWinAscent
;
6815 descent
= pOS2
->usWinDescent
;
6818 font
->ntmCellHeight
= ascent
+ descent
;
6819 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6822 TM
.tmAscent
= font
->yMax
;
6823 TM
.tmDescent
= -font
->yMin
;
6824 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6826 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6827 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6828 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6829 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6832 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6835 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6837 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6838 ((ascent
+ descent
) -
6839 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6841 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6842 if (TM
.tmAveCharWidth
== 0) {
6843 TM
.tmAveCharWidth
= 1;
6845 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6846 TM
.tmWeight
= FW_REGULAR
;
6847 if (font
->fake_bold
)
6848 TM
.tmWeight
= FW_BOLD
;
6851 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6853 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6854 TM
.tmWeight
= pOS2
->usWeightClass
;
6856 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6857 TM
.tmWeight
= pOS2
->usWeightClass
;
6860 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6861 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6862 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6863 * symbol range to 0 - f0ff
6866 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6871 case 1257: /* Baltic */
6872 TM
.tmLastChar
= 0xf8fd;
6875 TM
.tmLastChar
= 0xf0ff;
6877 TM
.tmBreakChar
= 0x20;
6878 TM
.tmDefaultChar
= 0x1f;
6882 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6883 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6885 if(pOS2
->usFirstCharIndex
<= 1)
6886 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6887 else if (pOS2
->usFirstCharIndex
> 0xff)
6888 TM
.tmBreakChar
= 0x20;
6890 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6891 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6893 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6894 TM
.tmUnderlined
= font
->underline
;
6895 TM
.tmStruckOut
= font
->strikeout
;
6897 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6898 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6899 (pOS2
->version
== 0xFFFFU
||
6900 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6901 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6903 TM
.tmPitchAndFamily
= 0;
6905 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6907 case PAN_FAMILY_SCRIPT
:
6908 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6911 case PAN_FAMILY_DECORATIVE
:
6912 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6917 case PAN_FAMILY_TEXT_DISPLAY
:
6918 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6919 /* which is clearly not what the panose spec says. */
6921 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6922 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6923 TM
.tmPitchAndFamily
= FF_MODERN
;
6926 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6931 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6934 case PAN_SERIF_COVE
:
6935 case PAN_SERIF_OBTUSE_COVE
:
6936 case PAN_SERIF_SQUARE_COVE
:
6937 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6938 case PAN_SERIF_SQUARE
:
6939 case PAN_SERIF_THIN
:
6940 case PAN_SERIF_BONE
:
6941 case PAN_SERIF_EXAGGERATED
:
6942 case PAN_SERIF_TRIANGLE
:
6943 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6946 case PAN_SERIF_NORMAL_SANS
:
6947 case PAN_SERIF_OBTUSE_SANS
:
6948 case PAN_SERIF_PERP_SANS
:
6949 case PAN_SERIF_FLARED
:
6950 case PAN_SERIF_ROUNDED
:
6951 TM
.tmPitchAndFamily
|= FF_SWISS
;
6958 if(FT_IS_SCALABLE(ft_face
))
6959 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6961 if(FT_IS_SFNT(ft_face
))
6963 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6964 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6966 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6969 TM
.tmCharSet
= font
->charset
;
6971 font
->potm
->otmFiller
= 0;
6972 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6973 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6974 font
->potm
->otmfsType
= pOS2
->fsType
;
6975 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6976 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6977 font
->potm
->otmItalicAngle
= 0; /* POST table */
6978 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6979 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6980 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6981 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6982 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6983 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6984 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6985 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6986 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6987 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6988 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6989 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6990 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6991 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6992 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6993 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6994 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6995 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6996 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6997 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6998 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6999 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
7000 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
7001 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
7003 font
->potm
->otmsUnderscoreSize
= 0;
7004 font
->potm
->otmsUnderscorePosition
= 0;
7006 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
7007 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
7011 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7012 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7013 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7014 strcpyW((WCHAR
*)cp
, family_nameW
);
7016 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7017 strcpyW((WCHAR
*)cp
, style_nameW
);
7019 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7020 strcpyW((WCHAR
*)cp
, face_nameW
);
7022 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7023 strcpyW((WCHAR
*)cp
, full_nameW
);
7027 HeapFree(GetProcessHeap(), 0, style_nameW
);
7028 HeapFree(GetProcessHeap(), 0, family_nameW
);
7029 HeapFree(GetProcessHeap(), 0, face_nameW
);
7030 HeapFree(GetProcessHeap(), 0, full_nameW
);
7034 /*************************************************************
7035 * freetype_GetGlyphOutline
7037 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7038 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7040 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7046 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7047 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7051 EnterCriticalSection( &freetype_cs
);
7052 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7053 LeaveCriticalSection( &freetype_cs
);
7057 /*************************************************************
7058 * freetype_GetTextMetrics
7060 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7062 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7067 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7068 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7072 EnterCriticalSection( &freetype_cs
);
7073 ret
= get_text_metrics( physdev
->font
, metrics
);
7074 LeaveCriticalSection( &freetype_cs
);
7078 /*************************************************************
7079 * freetype_GetOutlineTextMetrics
7081 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7083 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7088 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7089 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7092 TRACE("font=%p\n", physdev
->font
);
7094 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7097 EnterCriticalSection( &freetype_cs
);
7099 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7101 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7103 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7104 scale_outline_font_metrics(physdev
->font
, potm
);
7106 ret
= physdev
->font
->potm
->otmSize
;
7108 LeaveCriticalSection( &freetype_cs
);
7112 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7114 child
->font
= alloc_font();
7115 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7116 if(!child
->font
->ft_face
)
7118 free_font(child
->font
);
7123 child
->font
->font_desc
= font
->font_desc
;
7124 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7125 child
->font
->orientation
= font
->orientation
;
7126 child
->font
->scale_y
= font
->scale_y
;
7127 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7128 child
->font
->base_font
= font
;
7129 TRACE("created child font %p for base %p\n", child
->font
, font
);
7133 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
7136 CHILD_FONT
*child_font
;
7139 font
= font
->base_font
;
7141 *linked_font
= font
;
7143 if((*glyph
= get_glyph_index(font
, c
)))
7145 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7149 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7151 if(!child_font
->font
)
7152 if(!load_child_font(font
, child_font
))
7155 if(!child_font
->font
->ft_face
)
7157 g
= get_glyph_index(child_font
->font
, c
);
7158 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7162 *linked_font
= child_font
->font
;
7169 /*************************************************************
7170 * freetype_GetCharWidth
7172 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7174 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7178 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7182 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7183 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7186 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7189 EnterCriticalSection( &freetype_cs
);
7190 for(c
= firstChar
; c
<= lastChar
; c
++) {
7191 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7192 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7194 LeaveCriticalSection( &freetype_cs
);
7198 /*************************************************************
7199 * freetype_GetCharABCWidths
7201 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7203 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7206 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7210 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7211 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7214 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7217 EnterCriticalSection( &freetype_cs
);
7219 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7220 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7222 LeaveCriticalSection( &freetype_cs
);
7226 /*************************************************************
7227 * freetype_GetCharABCWidthsI
7229 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7231 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7234 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7238 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7239 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7242 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7246 EnterCriticalSection( &freetype_cs
);
7248 for(c
= 0; c
< count
; c
++, buffer
++)
7249 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7250 &gm
, buffer
, 0, NULL
, &identity
);
7252 LeaveCriticalSection( &freetype_cs
);
7256 /*************************************************************
7257 * freetype_GetTextExtentExPoint
7259 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7261 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7265 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7269 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7270 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7273 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7276 EnterCriticalSection( &freetype_cs
);
7278 for (idx
= pos
= 0; idx
< count
; idx
++)
7280 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7281 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7285 LeaveCriticalSection( &freetype_cs
);
7289 /*************************************************************
7290 * freetype_GetTextExtentExPointI
7292 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7294 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7298 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7302 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7303 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7306 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7309 EnterCriticalSection( &freetype_cs
);
7311 for (idx
= pos
= 0; idx
< count
; idx
++)
7313 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7314 &gm
, &abc
, 0, NULL
, &identity
);
7315 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7319 LeaveCriticalSection( &freetype_cs
);
7323 /*************************************************************
7324 * freetype_GetFontData
7326 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7328 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7332 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7333 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7336 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7337 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7338 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7340 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7343 /*************************************************************
7344 * freetype_GetTextFace
7346 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7349 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7353 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7354 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7357 n
= strlenW(physdev
->font
->name
) + 1;
7360 lstrcpynW(str
, physdev
->font
->name
, count
);
7366 /*************************************************************
7367 * freetype_GetTextCharsetInfo
7369 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7371 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7375 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7376 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7378 if (fs
) *fs
= physdev
->font
->fs
;
7379 return physdev
->font
->charset
;
7382 /* Retrieve a list of supported Unicode ranges for a given font.
7383 * Can be called with NULL gs to calculate the buffer size. Returns
7384 * the number of ranges found.
7386 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7388 DWORD num_ranges
= 0;
7390 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7393 FT_ULong char_code
, char_code_prev
;
7396 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7398 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7399 face
->num_glyphs
, glyph_code
, char_code
);
7401 if (!glyph_code
) return 0;
7405 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7406 gs
->ranges
[0].cGlyphs
= 0;
7407 gs
->cGlyphsSupported
= 0;
7413 if (char_code
< char_code_prev
)
7415 ERR("expected increasing char code from FT_Get_Next_Char\n");
7418 if (char_code
- char_code_prev
> 1)
7423 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7424 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7425 gs
->cGlyphsSupported
++;
7430 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7431 gs
->cGlyphsSupported
++;
7433 char_code_prev
= char_code
;
7434 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7438 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7443 /*************************************************************
7444 * freetype_GetFontUnicodeRanges
7446 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7448 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7449 DWORD size
, num_ranges
;
7453 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7454 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7457 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7458 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7461 glyphset
->cbThis
= size
;
7462 glyphset
->cRanges
= num_ranges
;
7463 glyphset
->flAccel
= 0;
7468 /*************************************************************
7469 * freetype_FontIsLinked
7471 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7473 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7478 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7479 return dev
->funcs
->pFontIsLinked( dev
);
7483 EnterCriticalSection( &freetype_cs
);
7484 ret
= !list_empty(&physdev
->font
->child_fonts
);
7485 LeaveCriticalSection( &freetype_cs
);
7489 /*************************************************************************
7490 * GetRasterizerCaps (GDI32.@)
7492 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7494 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7495 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7496 lprs
->nLanguageID
= 0;
7500 /*************************************************************
7501 * freetype_GdiRealizationInfo
7503 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7505 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7506 realization_info_t
*info
= ptr
;
7510 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7511 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7514 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7517 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7520 info
->cache_num
= physdev
->font
->cache_num
;
7521 info
->unknown2
= -1;
7525 /*************************************************************************
7526 * Kerning support for TrueType fonts
7528 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7530 struct TT_kern_table
7536 struct TT_kern_subtable
7545 USHORT horizontal
: 1;
7547 USHORT cross_stream
: 1;
7548 USHORT override
: 1;
7549 USHORT reserved1
: 4;
7555 struct TT_format0_kern_subtable
7559 USHORT entrySelector
;
7570 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7571 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7572 const USHORT
*glyph_to_char
,
7573 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7576 const struct TT_kern_pair
*tt_kern_pair
;
7578 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7580 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7582 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7583 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7584 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7586 if (!kern_pair
|| !cPairs
)
7589 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7591 nPairs
= min(nPairs
, cPairs
);
7593 for (i
= 0; i
< nPairs
; i
++)
7595 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7596 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7597 /* this algorithm appears to better match what Windows does */
7598 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7599 if (kern_pair
->iKernAmount
< 0)
7601 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7602 kern_pair
->iKernAmount
-= font
->ppem
;
7604 else if (kern_pair
->iKernAmount
> 0)
7606 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7607 kern_pair
->iKernAmount
+= font
->ppem
;
7609 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7611 TRACE("left %u right %u value %d\n",
7612 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7616 TRACE("copied %u entries\n", nPairs
);
7620 /*************************************************************
7621 * freetype_GetKerningPairs
7623 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7627 const struct TT_kern_table
*tt_kern_table
;
7628 const struct TT_kern_subtable
*tt_kern_subtable
;
7630 USHORT
*glyph_to_char
;
7632 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7634 if (!(font
= physdev
->font
))
7636 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7637 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7641 EnterCriticalSection( &freetype_cs
);
7642 if (font
->total_kern_pairs
!= (DWORD
)-1)
7644 if (cPairs
&& kern_pair
)
7646 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7647 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7649 else cPairs
= font
->total_kern_pairs
;
7651 LeaveCriticalSection( &freetype_cs
);
7655 font
->total_kern_pairs
= 0;
7657 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7659 if (length
== GDI_ERROR
)
7661 TRACE("no kerning data in the font\n");
7662 LeaveCriticalSection( &freetype_cs
);
7666 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7669 WARN("Out of memory\n");
7670 LeaveCriticalSection( &freetype_cs
);
7674 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7676 /* build a glyph index to char code map */
7677 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7680 WARN("Out of memory allocating a glyph index to char code map\n");
7681 HeapFree(GetProcessHeap(), 0, buf
);
7682 LeaveCriticalSection( &freetype_cs
);
7686 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7692 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7694 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7695 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7699 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7701 /* FIXME: This doesn't match what Windows does: it does some fancy
7702 * things with duplicate glyph index to char code mappings, while
7703 * we just avoid overriding existing entries.
7705 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7706 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7708 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7715 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7716 for (n
= 0; n
<= 65535; n
++)
7717 glyph_to_char
[n
] = (USHORT
)n
;
7720 tt_kern_table
= buf
;
7721 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7722 TRACE("version %u, nTables %u\n",
7723 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7725 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7727 for (i
= 0; i
< nTables
; i
++)
7729 struct TT_kern_subtable tt_kern_subtable_copy
;
7731 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7732 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7733 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7735 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7736 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7737 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7739 /* According to the TrueType specification this is the only format
7740 * that will be properly interpreted by Windows and OS/2
7742 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7744 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7746 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7747 glyph_to_char
, NULL
, 0);
7748 font
->total_kern_pairs
+= new_chunk
;
7750 if (!font
->kern_pairs
)
7751 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7752 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7754 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7755 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7757 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7758 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7761 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7763 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7766 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7767 HeapFree(GetProcessHeap(), 0, buf
);
7769 if (cPairs
&& kern_pair
)
7771 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7772 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7774 else cPairs
= font
->total_kern_pairs
;
7776 LeaveCriticalSection( &freetype_cs
);
7780 static const struct gdi_dc_funcs freetype_funcs
=
7782 NULL
, /* pAbortDoc */
7783 NULL
, /* pAbortPath */
7784 NULL
, /* pAlphaBlend */
7785 NULL
, /* pAngleArc */
7788 NULL
, /* pBeginPath */
7789 NULL
, /* pBlendImage */
7791 NULL
, /* pCloseFigure */
7792 NULL
, /* pCreateCompatibleDC */
7793 freetype_CreateDC
, /* pCreateDC */
7794 freetype_DeleteDC
, /* pDeleteDC */
7795 NULL
, /* pDeleteObject */
7796 NULL
, /* pDeviceCapabilities */
7797 NULL
, /* pEllipse */
7799 NULL
, /* pEndPage */
7800 NULL
, /* pEndPath */
7801 freetype_EnumFonts
, /* pEnumFonts */
7802 NULL
, /* pEnumICMProfiles */
7803 NULL
, /* pExcludeClipRect */
7804 NULL
, /* pExtDeviceMode */
7805 NULL
, /* pExtEscape */
7806 NULL
, /* pExtFloodFill */
7807 NULL
, /* pExtSelectClipRgn */
7808 NULL
, /* pExtTextOut */
7809 NULL
, /* pFillPath */
7810 NULL
, /* pFillRgn */
7811 NULL
, /* pFlattenPath */
7812 freetype_FontIsLinked
, /* pFontIsLinked */
7813 NULL
, /* pFrameRgn */
7814 NULL
, /* pGdiComment */
7815 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7816 NULL
, /* pGetBoundsRect */
7817 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7818 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7819 freetype_GetCharWidth
, /* pGetCharWidth */
7820 NULL
, /* pGetDeviceCaps */
7821 NULL
, /* pGetDeviceGammaRamp */
7822 freetype_GetFontData
, /* pGetFontData */
7823 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7824 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7825 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7826 NULL
, /* pGetICMProfile */
7827 NULL
, /* pGetImage */
7828 freetype_GetKerningPairs
, /* pGetKerningPairs */
7829 NULL
, /* pGetNearestColor */
7830 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7831 NULL
, /* pGetPixel */
7832 NULL
, /* pGetSystemPaletteEntries */
7833 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7834 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7835 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7836 freetype_GetTextFace
, /* pGetTextFace */
7837 freetype_GetTextMetrics
, /* pGetTextMetrics */
7838 NULL
, /* pGradientFill */
7839 NULL
, /* pIntersectClipRect */
7840 NULL
, /* pInvertRgn */
7842 NULL
, /* pModifyWorldTransform */
7844 NULL
, /* pOffsetClipRgn */
7845 NULL
, /* pOffsetViewportOrg */
7846 NULL
, /* pOffsetWindowOrg */
7847 NULL
, /* pPaintRgn */
7850 NULL
, /* pPolyBezier */
7851 NULL
, /* pPolyBezierTo */
7852 NULL
, /* pPolyDraw */
7853 NULL
, /* pPolyPolygon */
7854 NULL
, /* pPolyPolyline */
7855 NULL
, /* pPolygon */
7856 NULL
, /* pPolyline */
7857 NULL
, /* pPolylineTo */
7858 NULL
, /* pPutImage */
7859 NULL
, /* pRealizeDefaultPalette */
7860 NULL
, /* pRealizePalette */
7861 NULL
, /* pRectangle */
7862 NULL
, /* pResetDC */
7863 NULL
, /* pRestoreDC */
7864 NULL
, /* pRoundRect */
7866 NULL
, /* pScaleViewportExt */
7867 NULL
, /* pScaleWindowExt */
7868 NULL
, /* pSelectBitmap */
7869 NULL
, /* pSelectBrush */
7870 NULL
, /* pSelectClipPath */
7871 freetype_SelectFont
, /* pSelectFont */
7872 NULL
, /* pSelectPalette */
7873 NULL
, /* pSelectPen */
7874 NULL
, /* pSetArcDirection */
7875 NULL
, /* pSetBkColor */
7876 NULL
, /* pSetBkMode */
7877 NULL
, /* pSetDCBrushColor */
7878 NULL
, /* pSetDCPenColor */
7879 NULL
, /* pSetDIBColorTable */
7880 NULL
, /* pSetDIBitsToDevice */
7881 NULL
, /* pSetDeviceClipping */
7882 NULL
, /* pSetDeviceGammaRamp */
7883 NULL
, /* pSetLayout */
7884 NULL
, /* pSetMapMode */
7885 NULL
, /* pSetMapperFlags */
7886 NULL
, /* pSetPixel */
7887 NULL
, /* pSetPolyFillMode */
7888 NULL
, /* pSetROP2 */
7889 NULL
, /* pSetRelAbs */
7890 NULL
, /* pSetStretchBltMode */
7891 NULL
, /* pSetTextAlign */
7892 NULL
, /* pSetTextCharacterExtra */
7893 NULL
, /* pSetTextColor */
7894 NULL
, /* pSetTextJustification */
7895 NULL
, /* pSetViewportExt */
7896 NULL
, /* pSetViewportOrg */
7897 NULL
, /* pSetWindowExt */
7898 NULL
, /* pSetWindowOrg */
7899 NULL
, /* pSetWorldTransform */
7900 NULL
, /* pStartDoc */
7901 NULL
, /* pStartPage */
7902 NULL
, /* pStretchBlt */
7903 NULL
, /* pStretchDIBits */
7904 NULL
, /* pStrokeAndFillPath */
7905 NULL
, /* pStrokePath */
7906 NULL
, /* pUnrealizePalette */
7907 NULL
, /* pWidenPath */
7908 NULL
, /* wine_get_wgl_driver */
7909 GDI_PRIORITY_FONT_DRV
/* priority */
7912 #else /* HAVE_FREETYPE */
7914 /*************************************************************************/
7916 BOOL
WineEngInit(void)
7921 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7923 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7927 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7929 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7933 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7935 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7939 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
7940 LPCWSTR font_file
, LPCWSTR font_path
)
7946 /*************************************************************************
7947 * GetRasterizerCaps (GDI32.@)
7949 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7951 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7953 lprs
->nLanguageID
= 0;
7957 #endif /* HAVE_FREETYPE */