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
;
269 DWORD font_data_size
;
273 FT_Fixed font_version
;
275 Bitmap_Size size
; /* set if face is a bitmap */
276 DWORD flags
; /* ADDFONT flags */
277 struct tagFamily
*family
;
278 /* Cached data for Enum */
279 struct enum_data
*cached_enum_data
;
282 #define ADDFONT_EXTERNAL_FONT 0x01
283 #define ADDFONT_ALLOW_BITMAP 0x02
284 #define ADDFONT_ADD_TO_CACHE 0x04
285 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
286 #define ADDFONT_VERTICAL_FONT 0x10
287 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
289 typedef struct tagFamily
{
291 unsigned int refcount
;
295 struct list
*replacement
;
300 ABC abc
; /* metrics of the unrotated char */
316 typedef struct tagGdiFont GdiFont
;
326 struct list unused_entry
;
327 unsigned int refcount
;
330 OUTLINETEXTMETRICW
*potm
;
331 DWORD total_kern_pairs
;
332 KERNINGPAIR
*kern_pairs
;
333 struct list child_fonts
;
335 /* the following members can be accessed without locking, they are never modified after creation */
337 struct font_mapping
*mapping
;
353 UINT ntmCellHeight
, ntmAvgWidth
;
362 const WCHAR
*font_name
;
367 struct enum_charset_element
{
370 WCHAR name
[LF_FACESIZE
];
373 struct enum_charset_list
{
375 struct enum_charset_element element
[32];
378 #define GM_BLOCK_SIZE 128
379 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
381 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
382 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
383 static unsigned int unused_font_count
;
384 #define UNUSED_CACHE_SIZE 10
385 static struct list system_links
= LIST_INIT(system_links
);
387 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
389 static struct list font_list
= LIST_INIT(font_list
);
391 struct freetype_physdev
393 struct gdi_physdev dev
;
397 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
399 return (struct freetype_physdev
*)dev
;
402 static const struct gdi_dc_funcs freetype_funcs
;
404 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
405 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
406 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
408 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
409 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
410 'W','i','n','d','o','w','s','\\',
411 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
412 'F','o','n','t','s','\0'};
414 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
415 'W','i','n','d','o','w','s',' ','N','T','\\',
416 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
417 'F','o','n','t','s','\0'};
419 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
420 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
421 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
422 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
424 static const WCHAR
* const SystemFontValues
[] = {
431 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
432 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
434 /* Interesting and well-known (frequently-assumed!) font names */
435 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
436 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 };
437 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
438 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
439 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
440 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
441 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
442 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
444 static const WCHAR arial
[] = {'A','r','i','a','l',0};
445 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
446 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};
447 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};
448 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
449 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
450 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
451 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
452 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
453 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
455 static const WCHAR
*default_serif_list
[] =
459 bitstream_vera_serif
,
463 static const WCHAR
*default_fixed_list
[] =
467 bitstream_vera_sans_mono
,
471 static const WCHAR
*default_sans_list
[] =
484 typedef struct tagFontSubst
{
490 /* Registry font cache key and value names */
491 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
492 'F','o','n','t','s',0};
493 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
494 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
495 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
496 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
497 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
498 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
499 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
500 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
501 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
502 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
503 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
504 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
505 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
506 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
507 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
520 static struct list mappings_list
= LIST_INIT( mappings_list
);
522 static UINT default_aa_flags
;
523 static HKEY hkey_font_cache
;
525 static CRITICAL_SECTION freetype_cs
;
526 static CRITICAL_SECTION_DEBUG critsect_debug
=
529 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
530 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
532 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
534 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
536 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
537 static BOOL use_default_fallback
= FALSE
;
539 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
540 static BOOL
get_outline_text_metrics(GdiFont
*font
);
541 static BOOL
get_bitmap_text_metrics(GdiFont
*font
);
542 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
543 static void remove_face_from_cache( Face
*face
);
545 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
546 'W','i','n','d','o','w','s',' ','N','T','\\',
547 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
548 'S','y','s','t','e','m','L','i','n','k',0};
550 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
551 'F','o','n','t','L','i','n','k','\\',
552 'S','y','s','t','e','m','L','i','n','k',0};
554 /****************************************
555 * Notes on .fon files
557 * The fonts System, FixedSys and Terminal are special. There are typically multiple
558 * versions installed for different resolutions and codepages. Windows stores which one to use
559 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
561 * FIXEDFON.FON FixedSys
563 * OEMFONT.FON Terminal
564 * LogPixels Current dpi set by the display control panel applet
565 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
566 * also has a LogPixels value that appears to mirror this)
568 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
569 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
570 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
571 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
572 * so that makes sense.
574 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
575 * to be mapped into the registry on Windows 2000 at least).
578 * ega80woa.fon=ega80850.fon
579 * ega40woa.fon=ega40850.fon
580 * cga80woa.fon=cga80850.fon
581 * cga40woa.fon=cga40850.fon
584 /* These are all structures needed for the GSUB table */
586 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
587 #define TATEGAKI_LOWER_BOUND 0x02F1
603 GSUB_ScriptRecord ScriptRecord
[1];
609 } GSUB_LangSysRecord
;
614 GSUB_LangSysRecord LangSysRecord
[1];
618 WORD LookupOrder
; /* Reserved */
619 WORD ReqFeatureIndex
;
621 WORD FeatureIndex
[1];
627 } GSUB_FeatureRecord
;
631 GSUB_FeatureRecord FeatureRecord
[1];
635 WORD FeatureParams
; /* Reserved */
637 WORD LookupListIndex
[1];
656 } GSUB_CoverageFormat1
;
661 WORD StartCoverageIndex
;
667 GSUB_RangeRecord RangeRecord
[1];
668 } GSUB_CoverageFormat2
;
671 WORD SubstFormat
; /* = 1 */
674 } GSUB_SingleSubstFormat1
;
677 WORD SubstFormat
; /* = 2 */
681 }GSUB_SingleSubstFormat2
;
683 #ifdef HAVE_CARBON_CARBON_H
684 static char *find_cache_dir(void)
688 static char cached_path
[MAX_PATH
];
689 static const char *wine
= "/Wine", *fonts
= "/Fonts";
691 if(*cached_path
) return cached_path
;
693 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
696 WARN("can't create cached data folder\n");
699 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
702 WARN("can't create cached data path\n");
706 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
708 ERR("Could not create full path\n");
712 strcat(cached_path
, wine
);
714 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
716 WARN("Couldn't mkdir %s\n", cached_path
);
720 strcat(cached_path
, fonts
);
721 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
723 WARN("Couldn't mkdir %s\n", cached_path
);
730 /******************************************************************
733 * Extracts individual TrueType font files from a Mac suitcase font
734 * and saves them into the user's caches directory (see
736 * Returns a NULL terminated array of filenames.
738 * We do this because they are apps that try to read ttf files
739 * themselves and they don't like Mac suitcase files.
741 static char **expand_mac_font(const char *path
)
748 const char *filename
;
752 unsigned int size
, max_size
;
755 TRACE("path %s\n", path
);
757 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
760 WARN("failed to get ref\n");
764 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
767 TRACE("no data fork, so trying resource fork\n");
768 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
771 TRACE("unable to open resource fork\n");
778 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
781 CloseResFile(res_ref
);
785 out_dir
= find_cache_dir();
787 filename
= strrchr(path
, '/');
788 if(!filename
) filename
= path
;
791 /* output filename has the form out_dir/filename_%04x.ttf */
792 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
799 unsigned short *num_faces_ptr
, num_faces
, face
;
802 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
804 fond
= Get1IndResource(fond_res
, idx
);
806 TRACE("got fond resource %d\n", idx
);
809 fam_rec
= *(FamRec
**)fond
;
810 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
811 num_faces
= GET_BE_WORD(*num_faces_ptr
);
813 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
814 TRACE("num faces %04x\n", num_faces
);
815 for(face
= 0; face
< num_faces
; face
++, assoc
++)
818 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
819 unsigned short size
, font_id
;
822 size
= GET_BE_WORD(assoc
->fontSize
);
823 font_id
= GET_BE_WORD(assoc
->fontID
);
826 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
830 TRACE("trying to load sfnt id %04x\n", font_id
);
831 sfnt
= GetResource(sfnt_res
, font_id
);
834 TRACE("can't get sfnt resource %04x\n", font_id
);
838 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
843 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
845 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
846 if(fd
!= -1 || errno
== EEXIST
)
850 unsigned char *sfnt_data
;
853 sfnt_data
= *(unsigned char**)sfnt
;
854 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
858 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
861 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
863 ret
.array
[ret
.size
++] = output
;
867 WARN("unable to create %s\n", output
);
868 HeapFree(GetProcessHeap(), 0, output
);
871 ReleaseResource(sfnt
);
874 ReleaseResource(fond
);
877 CloseResFile(res_ref
);
882 #endif /* HAVE_CARBON_CARBON_H */
884 static inline BOOL
is_win9x(void)
886 return GetVersion() & 0x80000000;
889 This function builds an FT_Fixed from a double. It fails if the absolute
890 value of the float number is greater than 32768.
892 static inline FT_Fixed
FT_FixedFromFloat(double f
)
898 This function builds an FT_Fixed from a FIXED. It simply put f.value
899 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
901 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
903 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
906 static BOOL
is_hinting_enabled(void)
908 static int enabled
= -1;
912 /* Use the >= 2.2.0 function if available */
913 if (pFT_Get_TrueType_Engine_Type
)
915 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
916 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
918 #ifdef FT_DRIVER_HAS_HINTER
921 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
922 FT_Module mod
= pFT_Get_Module(library
, "truetype");
923 enabled
= (mod
&& FT_DRIVER_HAS_HINTER(mod
));
926 else enabled
= FALSE
;
927 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
932 static BOOL
is_subpixel_rendering_enabled( void )
934 #ifdef HAVE_FREETYPE_FTLCDFIL_H
935 static int enabled
= -1;
938 enabled
= (pFT_Library_SetLcdFilter
&&
939 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
940 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
949 static const struct list
*get_face_list_from_family(const Family
*family
)
951 if (!list_empty(&family
->faces
))
952 return &family
->faces
;
954 return family
->replacement
;
957 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
963 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
965 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
967 const struct list
*face_list
;
968 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
970 face_list
= get_face_list_from_family(family
);
971 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
975 file
= strrchrW(face
->file
, '/');
980 if(strcmpiW(file
, file_name
)) continue;
988 static Family
*find_family_from_name(const WCHAR
*name
)
992 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
994 if(!strcmpiW(family
->FamilyName
, name
))
1001 static Family
*find_family_from_any_name(const WCHAR
*name
)
1005 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1007 if(!strcmpiW(family
->FamilyName
, name
))
1009 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1016 static void DumpSubstList(void)
1020 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1022 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1023 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1024 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1026 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1027 debugstr_w(psub
->to
.name
));
1032 static LPWSTR
strdupW(LPCWSTR p
)
1035 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1036 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1037 memcpy(ret
, p
, len
);
1041 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1046 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1048 if(!strcmpiW(element
->from
.name
, from_name
) &&
1049 (element
->from
.charset
== from_charset
||
1050 element
->from
.charset
== -1))
1057 #define ADD_FONT_SUBST_FORCE 1
1059 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1061 FontSubst
*from_exist
, *to_exist
;
1063 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1065 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1067 list_remove(&from_exist
->entry
);
1068 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1069 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1070 HeapFree(GetProcessHeap(), 0, from_exist
);
1076 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1080 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1081 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1084 list_add_tail(subst_list
, &subst
->entry
);
1089 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1090 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1091 HeapFree(GetProcessHeap(), 0, subst
);
1095 static WCHAR
*towstr(UINT cp
, const char *str
)
1100 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1101 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1102 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1106 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1108 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1109 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1110 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1114 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1116 CHAR
*p
= strrchr(str
, ',');
1120 nc
->charset
= strtol(p
+1, NULL
, 10);
1123 nc
->name
= towstr(CP_ACP
, str
);
1126 static void LoadSubstList(void)
1130 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1134 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1135 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1136 &hkey
) == ERROR_SUCCESS
) {
1138 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1139 &valuelen
, &datalen
, NULL
, NULL
);
1141 valuelen
++; /* returned value doesn't include room for '\0' */
1142 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1143 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1147 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1148 &dlen
) == ERROR_SUCCESS
) {
1149 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1151 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1152 split_subst_info(&psub
->from
, value
);
1153 split_subst_info(&psub
->to
, data
);
1155 /* Win 2000 doesn't allow mapping between different charsets
1156 or mapping of DEFAULT_CHARSET */
1157 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1158 psub
->to
.charset
== DEFAULT_CHARSET
) {
1159 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1160 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1161 HeapFree(GetProcessHeap(), 0, psub
);
1163 add_font_subst(&font_subst_list
, psub
, 0);
1165 /* reset dlen and vlen */
1169 HeapFree(GetProcessHeap(), 0, data
);
1170 HeapFree(GetProcessHeap(), 0, value
);
1176 /*****************************************************************
1177 * get_name_table_entry
1179 * Supply the platform, encoding, language and name ids in req
1180 * and if the name exists the function will fill in the string
1181 * and string_len members. The string is owned by FreeType so
1182 * don't free it. Returns TRUE if the name is found else FALSE.
1184 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1187 FT_UInt num_names
, name_index
;
1189 if(FT_IS_SFNT(ft_face
))
1191 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1193 for(name_index
= 0; name_index
< num_names
; name_index
++)
1195 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1197 if((name
.platform_id
== req
->platform_id
) &&
1198 ((name
.encoding_id
== TT_MS_ID_UNICODE_CS
) || (name
.encoding_id
== TT_MS_ID_SYMBOL_CS
)) &&
1199 (name
.language_id
== req
->language_id
) &&
1200 (name
.name_id
== req
->name_id
))
1202 req
->string
= name
.string
;
1203 req
->string_len
= name
.string_len
;
1210 req
->string_len
= 0;
1214 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1219 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1220 name
.language_id
= language_id
;
1221 name
.name_id
= name_id
;
1223 if(get_name_table_entry(ft_face
, &name
))
1227 /* String is not nul terminated and string_len is a byte length. */
1228 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1229 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1231 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1232 ret
[i
] = GET_BE_WORD(*tmp
);
1235 TRACE("Got localised name %s\n", debugstr_w(ret
));
1241 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1243 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1244 if (f1
->scalable
) return TRUE
;
1245 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1246 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1249 static void release_family( Family
*family
)
1251 if (--family
->refcount
) return;
1252 assert( list_empty( &family
->faces
));
1253 list_remove( &family
->entry
);
1254 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1255 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1256 HeapFree( GetProcessHeap(), 0, family
);
1259 static void release_face( Face
*face
)
1261 if (--face
->refcount
) return;
1264 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1265 list_remove( &face
->entry
);
1266 release_family( face
->family
);
1268 HeapFree( GetProcessHeap(), 0, face
->file
);
1269 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1270 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1271 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1272 HeapFree( GetProcessHeap(), 0, face
);
1275 static inline int style_order(const Face
*face
)
1277 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1285 case NTM_BOLD
| NTM_ITALIC
:
1288 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1289 debugstr_w(face
->family
->FamilyName
),
1290 debugstr_w(face
->StyleName
),
1296 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1300 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1302 if (faces_equal( face
, cursor
))
1304 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1305 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1306 cursor
->font_version
, face
->font_version
);
1308 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1311 TRACE("Font %s already in list, refcount now %d\n",
1312 debugstr_w(face
->file
), cursor
->refcount
);
1315 if (face
->font_version
<= cursor
->font_version
)
1317 TRACE("Original font %s is newer so skipping %s\n",
1318 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1323 TRACE("Replacing original %s with %s\n",
1324 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1325 list_add_before( &cursor
->entry
, &face
->entry
);
1326 face
->family
= family
;
1329 release_face( cursor
);
1334 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1336 if (style_order( face
) < style_order( cursor
)) break;
1339 list_add_before( &cursor
->entry
, &face
->entry
);
1340 face
->family
= family
;
1346 /****************************************************************
1347 * NB This function stores the ptrs to the strings to save copying.
1348 * Don't free them after calling.
1350 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1352 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1353 family
->refcount
= 1;
1354 family
->FamilyName
= name
;
1355 family
->EnglishName
= english_name
;
1356 list_init( &family
->faces
);
1357 family
->replacement
= &family
->faces
;
1358 list_add_tail( &font_list
, &family
->entry
);
1363 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1365 DWORD type
, size
= sizeof(DWORD
);
1367 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1368 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1371 return ERROR_BAD_CONFIGURATION
;
1373 return ERROR_SUCCESS
;
1376 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1378 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1381 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1383 DWORD needed
, strike_index
= 0;
1386 /* If we have a File Name key then this is a real font, not just the parent
1387 key of a bunch of non-scalable strikes */
1388 needed
= buffer_size
;
1389 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1392 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1393 face
->cached_enum_data
= NULL
;
1394 face
->family
= NULL
;
1397 face
->file
= strdupW( buffer
);
1398 face
->StyleName
= strdupW(face_name
);
1400 needed
= buffer_size
;
1401 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1402 face
->FullName
= strdupW( buffer
);
1404 face
->FullName
= NULL
;
1406 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1407 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1408 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1409 reg_load_dword(hkey_face
, face_flags_value
, (DWORD
*)&face
->flags
);
1411 needed
= sizeof(face
->fs
);
1412 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1414 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1416 face
->scalable
= TRUE
;
1417 memset(&face
->size
, 0, sizeof(face
->size
));
1421 face
->scalable
= FALSE
;
1422 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1423 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1424 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1425 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1426 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1428 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1429 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1430 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1433 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1434 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1435 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1436 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1438 if (insert_face_in_family_list(face
, family
))
1439 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1441 release_face( face
);
1444 /* load bitmap strikes */
1446 needed
= buffer_size
;
1447 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1449 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1451 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1452 RegCloseKey(hkey_strike
);
1454 needed
= buffer_size
;
1458 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1460 DWORD size
, family_index
= 0;
1465 size
= sizeof(buffer
);
1466 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1468 WCHAR
*english_family
= NULL
;
1469 WCHAR
*family_name
= strdupW( buffer
);
1470 DWORD face_index
= 0;
1472 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1473 TRACE("opened family key %s\n", debugstr_w(family_name
));
1474 size
= sizeof(buffer
);
1475 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1476 english_family
= strdupW( buffer
);
1478 family
= create_family(family_name
, english_family
);
1482 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1483 subst
->from
.name
= strdupW(english_family
);
1484 subst
->from
.charset
= -1;
1485 subst
->to
.name
= strdupW(family_name
);
1486 subst
->to
.charset
= -1;
1487 add_font_subst(&font_subst_list
, subst
, 0);
1490 size
= sizeof(buffer
);
1491 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1493 WCHAR
*face_name
= strdupW( buffer
);
1496 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1498 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1499 RegCloseKey(hkey_face
);
1501 HeapFree( GetProcessHeap(), 0, face_name
);
1502 size
= sizeof(buffer
);
1504 RegCloseKey(hkey_family
);
1505 release_family( family
);
1506 size
= sizeof(buffer
);
1510 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1513 HKEY hkey_wine_fonts
;
1515 /* We don't want to create the fonts key as volatile, so open this first */
1516 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1517 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1518 if(ret
!= ERROR_SUCCESS
)
1520 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1524 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1525 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1526 RegCloseKey(hkey_wine_fonts
);
1530 static void add_face_to_cache(Face
*face
)
1532 HKEY hkey_family
, hkey_face
;
1533 WCHAR
*face_key_name
;
1535 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1536 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1537 if(face
->family
->EnglishName
)
1538 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1539 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1542 face_key_name
= face
->StyleName
;
1545 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1546 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1547 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1549 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1552 HeapFree(GetProcessHeap(), 0, face_key_name
);
1554 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1555 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1557 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1558 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1560 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1561 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1562 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1563 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1565 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1569 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1570 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1571 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1572 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1573 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1574 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1576 RegCloseKey(hkey_face
);
1577 RegCloseKey(hkey_family
);
1580 static void remove_face_from_cache( Face
*face
)
1584 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1588 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1592 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1593 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1594 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1595 RegDeleteKeyW( hkey_family
, face_key_name
);
1596 HeapFree(GetProcessHeap(), 0, face_key_name
);
1598 RegCloseKey(hkey_family
);
1601 static WCHAR
*prepend_at(WCHAR
*family
)
1608 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1610 strcpyW(str
+ 1, family
);
1611 HeapFree(GetProcessHeap(), 0, family
);
1615 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1617 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1618 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1620 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1626 else if (!strcmpiW( *name
, *english
))
1628 HeapFree( GetProcessHeap(), 0, *english
);
1634 *name
= prepend_at( *name
);
1635 *english
= prepend_at( *english
);
1639 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1642 WCHAR
*name
, *english_name
;
1644 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1646 family
= find_family_from_name( name
);
1650 family
= create_family( name
, english_name
);
1653 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1654 subst
->from
.name
= strdupW( english_name
);
1655 subst
->from
.charset
= -1;
1656 subst
->to
.name
= strdupW( name
);
1657 subst
->to
.charset
= -1;
1658 add_font_subst( &font_subst_list
, subst
, 0 );
1663 HeapFree( GetProcessHeap(), 0, name
);
1664 HeapFree( GetProcessHeap(), 0, english_name
);
1671 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1673 FT_Fixed version
= 0;
1676 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1677 if (header
) version
= header
->Font_Revision
;
1682 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1685 FT_ULong table_size
= 0;
1687 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1688 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1689 if (flags
== 0) flags
= NTM_REGULAR
;
1691 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1692 flags
|= NTM_PS_OPENTYPE
;
1697 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1699 int internal_leading
= 0;
1700 FT_WinFNT_HeaderRec winfnt_header
;
1702 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1703 internal_leading
= winfnt_header
.internal_leading
;
1705 return internal_leading
;
1708 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1713 FT_WinFNT_HeaderRec winfnt_header
;
1716 memset( fs
, 0, sizeof(*fs
) );
1718 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1721 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1722 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1723 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1724 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1726 if (os2
->version
== 0)
1728 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1729 fs
->fsCsb
[0] = FS_LATIN1
;
1731 fs
->fsCsb
[0] = FS_SYMBOL
;
1735 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1736 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1741 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1743 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1744 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1745 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1750 if (fs
->fsCsb
[0] == 0)
1752 /* let's see if we can find any interesting cmaps */
1753 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1755 switch (ft_face
->charmaps
[i
]->encoding
)
1757 case FT_ENCODING_UNICODE
:
1758 case FT_ENCODING_APPLE_ROMAN
:
1759 fs
->fsCsb
[0] |= FS_LATIN1
;
1761 case FT_ENCODING_MS_SYMBOL
:
1762 fs
->fsCsb
[0] |= FS_SYMBOL
;
1771 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1775 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1776 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1779 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1780 if (!face
->StyleName
)
1781 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1782 if (!face
->StyleName
)
1784 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1787 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1788 if (!face
->FullName
)
1789 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1790 if (flags
& ADDFONT_VERTICAL_FONT
)
1791 face
->FullName
= prepend_at( face
->FullName
);
1797 face
->file
= towstr( CP_UNIXCP
, file
);
1798 face
->font_data_ptr
= NULL
;
1799 face
->font_data_size
= 0;
1800 if (!stat( file
, &st
))
1802 face
->dev
= st
.st_dev
;
1803 face
->ino
= st
.st_ino
;
1809 face
->font_data_ptr
= font_data_ptr
;
1810 face
->font_data_size
= font_data_size
;
1813 face
->face_index
= face_index
;
1814 get_fontsig( ft_face
, &face
->fs
);
1815 face
->ntmFlags
= get_ntm_flags( ft_face
);
1816 face
->font_version
= get_font_version( ft_face
);
1818 if (FT_IS_SCALABLE( ft_face
))
1820 memset( &face
->size
, 0, sizeof(face
->size
) );
1821 face
->scalable
= TRUE
;
1825 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1826 size
->height
, size
->width
, size
->size
>> 6,
1827 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1828 face
->size
.height
= size
->height
;
1829 face
->size
.width
= size
->width
;
1830 face
->size
.size
= size
->size
;
1831 face
->size
.x_ppem
= size
->x_ppem
;
1832 face
->size
.y_ppem
= size
->y_ppem
;
1833 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1834 face
->scalable
= FALSE
;
1837 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1838 face
->flags
= flags
;
1839 face
->family
= NULL
;
1840 face
->cached_enum_data
= NULL
;
1842 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1843 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1844 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1845 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1850 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1851 FT_Long face_index
, DWORD flags
)
1856 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
1857 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
1858 if (insert_face_in_family_list( face
, family
))
1860 if (flags
& ADDFONT_ADD_TO_CACHE
)
1861 add_face_to_cache( face
);
1863 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1864 debugstr_w(face
->StyleName
));
1866 release_face( face
);
1867 release_family( family
);
1870 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1871 FT_Long face_index
, BOOL allow_bitmap
)
1879 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1880 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1884 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1885 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1890 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1894 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1895 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1897 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1901 if (!FT_IS_SFNT( ft_face
))
1903 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1905 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1911 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1912 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1913 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1915 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1916 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1920 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1921 we don't want to load these. */
1922 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1926 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1928 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1934 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1936 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1942 pFT_Done_Face( ft_face
);
1946 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1949 FT_Long face_index
= 0, num_faces
;
1952 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1953 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1955 #ifdef HAVE_CARBON_CARBON_H
1958 char **mac_list
= expand_mac_font(file
);
1961 BOOL had_one
= FALSE
;
1963 for(cursor
= mac_list
; *cursor
; cursor
++)
1966 AddFontToList(*cursor
, NULL
, 0, flags
);
1967 HeapFree(GetProcessHeap(), 0, *cursor
);
1969 HeapFree(GetProcessHeap(), 0, mac_list
);
1974 #endif /* HAVE_CARBON_CARBON_H */
1977 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
1978 if (!ft_face
) return 0;
1980 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1982 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1983 pFT_Done_Face(ft_face
);
1987 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
1990 if (FT_HAS_VERTICAL(ft_face
))
1992 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
1993 flags
| ADDFONT_VERTICAL_FONT
);
1997 num_faces
= ft_face
->num_faces
;
1998 pFT_Done_Face(ft_face
);
1999 } while(num_faces
> ++face_index
);
2003 static int remove_font_resource( const char *file
, DWORD flags
)
2005 Family
*family
, *family_next
;
2006 Face
*face
, *face_next
;
2010 if (stat( file
, &st
) == -1) return 0;
2011 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2014 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2016 if (!face
->file
) continue;
2017 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2018 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2020 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2021 release_face( face
);
2025 release_family( family
);
2030 static void DumpFontList(void)
2035 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2036 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2037 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2038 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2040 TRACE(" %d", face
->size
.height
);
2047 /***********************************************************
2048 * The replacement list is a way to map an entire font
2049 * family onto another family. For example adding
2051 * [HKCU\Software\Wine\Fonts\Replacements]
2052 * "Wingdings"="Winedings"
2054 * would enumerate the Winedings font both as Winedings and
2055 * Wingdings. However if a real Wingdings font is present the
2056 * replacement does not take place.
2059 static void LoadReplaceList(void)
2062 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2066 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2067 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2069 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2070 &valuelen
, &datalen
, NULL
, NULL
);
2072 valuelen
++; /* returned value doesn't include room for '\0' */
2073 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2074 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2078 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2079 &dlen
) == ERROR_SUCCESS
) {
2080 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2081 /* "NewName"="Oldname" */
2082 if(!find_family_from_any_name(value
))
2084 Family
* const family
= find_family_from_any_name(data
);
2087 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2088 if (new_family
!= NULL
)
2090 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2091 new_family
->FamilyName
= strdupW(value
);
2092 new_family
->EnglishName
= NULL
;
2093 list_init(&new_family
->faces
);
2094 new_family
->replacement
= &family
->faces
;
2095 list_add_tail(&font_list
, &new_family
->entry
);
2100 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2105 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2107 /* reset dlen and vlen */
2111 HeapFree(GetProcessHeap(), 0, data
);
2112 HeapFree(GetProcessHeap(), 0, value
);
2117 static const WCHAR
*font_links_list
[] =
2119 Lucida_Sans_Unicode
,
2120 Microsoft_Sans_Serif
,
2124 static const struct font_links_defaults_list
2126 /* Keyed off substitution for "MS Shell Dlg" */
2127 const WCHAR
*shelldlg
;
2128 /* Maximum of four substitutes, plus terminating NULL pointer */
2129 const WCHAR
*substitutes
[5];
2130 } font_links_defaults_list
[] =
2132 /* Non East-Asian */
2133 { Tahoma
, /* FIXME unverified ordering */
2134 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2136 /* Below lists are courtesy of
2137 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2141 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2143 /* Chinese Simplified */
2145 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2149 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2151 /* Chinese Traditional */
2153 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2158 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2160 SYSTEM_LINKS
*font_link
;
2162 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2164 if(!strcmpiW(font_link
->font_name
, name
))
2171 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2182 SYSTEM_LINKS
*font_link
;
2184 psub
= get_font_subst(&font_subst_list
, name
, -1);
2185 /* Don't store fonts that are only substitutes for other fonts */
2188 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2192 font_link
= find_font_link(name
);
2193 if (font_link
== NULL
)
2195 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2196 font_link
->font_name
= strdupW(name
);
2197 list_init(&font_link
->links
);
2198 list_add_tail(&system_links
, &font_link
->entry
);
2201 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2202 for (i
= 0; values
[i
] != NULL
; i
++)
2204 const struct list
*face_list
;
2205 CHILD_FONT
*child_font
;
2208 if (!strcmpiW(name
,value
))
2210 psub
= get_font_subst(&font_subst_list
, value
, -1);
2212 value
= psub
->to
.name
;
2213 family
= find_family_from_name(value
);
2217 /* Use first extant filename for this Family */
2218 face_list
= get_face_list_from_family(family
);
2219 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2223 file
= strrchrW(face
->file
, '/');
2232 face
= find_face_from_filename(file
, value
);
2235 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2239 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2240 child_font
->face
= face
;
2241 child_font
->font
= NULL
;
2242 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2243 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2244 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2245 child_font
->face
->face_index
);
2246 list_add_tail(&font_link
->links
, &child_font
->entry
);
2248 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2254 /*************************************************************
2257 static BOOL
init_system_links(void)
2261 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2262 WCHAR
*value
, *data
;
2263 WCHAR
*entry
, *next
;
2264 SYSTEM_LINKS
*font_link
, *system_font_link
;
2265 CHILD_FONT
*child_font
;
2266 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2267 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2268 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2273 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2275 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2276 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2277 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2278 val_len
= max_val
+ 1;
2279 data_len
= max_data
;
2281 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2283 psub
= get_font_subst(&font_subst_list
, value
, -1);
2284 /* Don't store fonts that are only substitutes for other fonts */
2287 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2290 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2291 font_link
->font_name
= strdupW(value
);
2292 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2293 list_init(&font_link
->links
);
2294 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2297 CHILD_FONT
*child_font
;
2299 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2301 next
= entry
+ strlenW(entry
) + 1;
2303 face_name
= strchrW(entry
, ',');
2307 while(isspaceW(*face_name
))
2310 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2312 face_name
= psub
->to
.name
;
2314 face
= find_face_from_filename(entry
, face_name
);
2317 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2321 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2322 child_font
->face
= face
;
2323 child_font
->font
= NULL
;
2324 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2325 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2326 TRACE("Adding file %s index %ld\n",
2327 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2328 list_add_tail(&font_link
->links
, &child_font
->entry
);
2330 list_add_tail(&system_links
, &font_link
->entry
);
2332 val_len
= max_val
+ 1;
2333 data_len
= max_data
;
2336 HeapFree(GetProcessHeap(), 0, value
);
2337 HeapFree(GetProcessHeap(), 0, data
);
2342 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2344 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2348 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2350 const FontSubst
*psub2
;
2351 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2353 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2355 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2356 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2358 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2359 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2361 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2363 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2369 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2372 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2373 system_font_link
->font_name
= strdupW(System
);
2374 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2375 list_init(&system_font_link
->links
);
2377 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2380 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2381 child_font
->face
= face
;
2382 child_font
->font
= NULL
;
2383 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2384 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2385 TRACE("Found Tahoma in %s index %ld\n",
2386 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2387 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2389 font_link
= find_font_link(Tahoma
);
2390 if (font_link
!= NULL
)
2392 CHILD_FONT
*font_link_entry
;
2393 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2395 CHILD_FONT
*new_child
;
2396 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2397 new_child
->face
= font_link_entry
->face
;
2398 new_child
->font
= NULL
;
2399 new_child
->face
->refcount
++;
2400 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2401 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2402 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2405 list_add_tail(&system_links
, &system_font_link
->entry
);
2409 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2412 struct dirent
*dent
;
2413 char path
[MAX_PATH
];
2415 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2417 dir
= opendir(dirname
);
2419 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2422 while((dent
= readdir(dir
)) != NULL
) {
2423 struct stat statbuf
;
2425 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2428 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2430 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2432 if(stat(path
, &statbuf
) == -1)
2434 WARN("Can't stat %s\n", debugstr_a(path
));
2437 if(S_ISDIR(statbuf
.st_mode
))
2438 ReadFontDir(path
, external_fonts
);
2441 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2442 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2443 AddFontToList(path
, NULL
, 0, addfont_flags
);
2450 #ifdef SONAME_LIBFONTCONFIG
2452 static BOOL fontconfig_enabled
;
2454 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2460 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2461 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2463 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2467 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2468 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2469 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2470 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2471 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2477 static void init_fontconfig(void)
2479 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2483 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2487 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2488 LOAD_FUNCPTR(FcConfigSubstitute
);
2489 LOAD_FUNCPTR(FcFontList
);
2490 LOAD_FUNCPTR(FcFontSetDestroy
);
2491 LOAD_FUNCPTR(FcInit
);
2492 LOAD_FUNCPTR(FcObjectSetAdd
);
2493 LOAD_FUNCPTR(FcObjectSetCreate
);
2494 LOAD_FUNCPTR(FcObjectSetDestroy
);
2495 LOAD_FUNCPTR(FcPatternCreate
);
2496 LOAD_FUNCPTR(FcPatternDestroy
);
2497 LOAD_FUNCPTR(FcPatternGetBool
);
2498 LOAD_FUNCPTR(FcPatternGetInteger
);
2499 LOAD_FUNCPTR(FcPatternGetString
);
2504 FcPattern
*pattern
= pFcPatternCreate();
2505 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2506 default_aa_flags
= parse_aa_pattern( pattern
);
2507 pFcPatternDestroy( pattern
);
2508 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2509 fontconfig_enabled
= TRUE
;
2513 static void load_fontconfig_fonts(void)
2522 if (!fontconfig_enabled
) return;
2524 pat
= pFcPatternCreate();
2525 os
= pFcObjectSetCreate();
2526 pFcObjectSetAdd(os
, FC_FILE
);
2527 pFcObjectSetAdd(os
, FC_SCALABLE
);
2528 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2529 pFcObjectSetAdd(os
, FC_RGBA
);
2530 fontset
= pFcFontList(NULL
, pat
, os
);
2531 if(!fontset
) return;
2532 for(i
= 0; i
< fontset
->nfont
; i
++) {
2536 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2539 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2541 /* We're just interested in OT/TT fonts for now, so this hack just
2542 picks up the scalable fonts without extensions .pf[ab] to save time
2543 loading every other font */
2545 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2547 TRACE("not scalable\n");
2551 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2552 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2554 len
= strlen( file
);
2555 if(len
< 4) continue;
2556 ext
= &file
[ len
- 3 ];
2557 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2558 AddFontToList(file
, NULL
, 0,
2559 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2561 pFcFontSetDestroy(fontset
);
2562 pFcObjectSetDestroy(os
);
2563 pFcPatternDestroy(pat
);
2566 #elif defined(HAVE_CARBON_CARBON_H)
2568 static void load_mac_font_callback(const void *value
, void *context
)
2570 CFStringRef pathStr
= value
;
2574 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2575 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2576 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2578 TRACE("font file %s\n", path
);
2579 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2581 HeapFree(GetProcessHeap(), 0, path
);
2584 static void load_mac_fonts(void)
2586 CFStringRef removeDupesKey
;
2587 CFBooleanRef removeDupesValue
;
2588 CFDictionaryRef options
;
2589 CTFontCollectionRef col
;
2591 CFMutableSetRef paths
;
2594 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2595 removeDupesValue
= kCFBooleanTrue
;
2596 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2597 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2598 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2599 if (options
) CFRelease(options
);
2602 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2606 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2610 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2614 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2617 WARN("CFSetCreateMutable failed\n");
2622 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2624 CTFontDescriptorRef desc
;
2633 desc
= CFArrayGetValueAtIndex(descs
, i
);
2635 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2636 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2637 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2638 if (!font
) continue;
2640 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2647 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2649 if (status
!= noErr
) continue;
2651 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2654 ext
= CFURLCopyPathExtension(url
);
2657 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2658 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2667 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2669 if (!path
) continue;
2671 CFSetAddValue(paths
, path
);
2677 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2683 static char *get_data_dir_path( LPCWSTR file
)
2685 char *unix_name
= NULL
;
2686 const char *data_dir
= wine_get_data_dir();
2688 if (!data_dir
) data_dir
= wine_get_build_dir();
2692 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2694 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2695 strcpy(unix_name
, data_dir
);
2696 strcat(unix_name
, "/fonts/");
2698 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2703 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2706 char *unix_name
= get_data_dir_path( file
);
2710 EnterCriticalSection( &freetype_cs
);
2711 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2712 LeaveCriticalSection( &freetype_cs
);
2713 HeapFree(GetProcessHeap(), 0, unix_name
);
2718 static char *get_winfonts_dir_path(LPCWSTR file
)
2720 static const WCHAR slashW
[] = {'\\','\0'};
2721 WCHAR windowsdir
[MAX_PATH
];
2723 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2724 strcatW(windowsdir
, fontsW
);
2725 strcatW(windowsdir
, slashW
);
2726 strcatW(windowsdir
, file
);
2727 return wine_get_unix_file_name( windowsdir
);
2730 static void load_system_fonts(void)
2733 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2734 const WCHAR
* const *value
;
2736 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2739 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2740 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2741 strcatW(windowsdir
, fontsW
);
2742 for(value
= SystemFontValues
; *value
; value
++) {
2743 dlen
= sizeof(data
);
2744 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2748 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2749 if((unixname
= wine_get_unix_file_name(pathW
))) {
2750 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2751 HeapFree(GetProcessHeap(), 0, unixname
);
2754 load_font_from_data_dir(data
);
2761 /*************************************************************
2763 * This adds registry entries for any externally loaded fonts
2764 * (fonts from fontconfig or FontDirs). It also deletes entries
2765 * of no longer existing fonts.
2768 static void update_reg_entries(void)
2770 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2776 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2778 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2779 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2780 ERR("Can't create Windows font reg key\n");
2784 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2785 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2786 ERR("Can't create Windows font reg key\n");
2790 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2791 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2792 ERR("Can't create external font reg key\n");
2796 /* enumerate the fonts and add external ones to the two keys */
2798 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2799 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2801 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
2805 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2806 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2807 strcpyW(valueW
, face
->FullName
);
2811 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2812 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2813 strcpyW(valueW
, family
->FamilyName
);
2816 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
2817 path
= wine_get_dos_file_name( buffer
);
2818 HeapFree( GetProcessHeap(), 0, buffer
);
2822 else if ((file
= strrchrW(face
->file
, '/')))
2827 len
= strlenW(file
) + 1;
2828 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2829 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2830 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2832 HeapFree(GetProcessHeap(), 0, path
);
2833 HeapFree(GetProcessHeap(), 0, valueW
);
2837 if(external_key
) RegCloseKey(external_key
);
2838 if(win9x_key
) RegCloseKey(win9x_key
);
2839 if(winnt_key
) RegCloseKey(winnt_key
);
2843 static void delete_external_font_keys(void)
2845 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2846 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2850 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2851 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2852 ERR("Can't create Windows font reg key\n");
2856 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2857 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2858 ERR("Can't create Windows font reg key\n");
2862 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2863 ERR("Can't create external font reg key\n");
2867 /* Delete all external fonts added last time */
2869 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2870 &valuelen
, &datalen
, NULL
, NULL
);
2871 valuelen
++; /* returned value doesn't include room for '\0' */
2872 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2873 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2875 dlen
= datalen
* sizeof(WCHAR
);
2878 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2879 &dlen
) == ERROR_SUCCESS
) {
2881 RegDeleteValueW(winnt_key
, valueW
);
2882 RegDeleteValueW(win9x_key
, valueW
);
2883 /* reset dlen and vlen */
2887 HeapFree(GetProcessHeap(), 0, data
);
2888 HeapFree(GetProcessHeap(), 0, valueW
);
2890 /* Delete the old external fonts key */
2891 RegCloseKey(external_key
);
2892 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2895 if(win9x_key
) RegCloseKey(win9x_key
);
2896 if(winnt_key
) RegCloseKey(winnt_key
);
2899 /*************************************************************
2900 * WineEngAddFontResourceEx
2903 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2909 if (ft_handle
) /* do it only if we have freetype up and running */
2913 EnterCriticalSection( &freetype_cs
);
2915 if((unixname
= wine_get_unix_file_name(file
)))
2917 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2919 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2920 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2921 HeapFree(GetProcessHeap(), 0, unixname
);
2923 if (!ret
&& !strchrW(file
, '\\')) {
2924 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2925 if ((unixname
= get_winfonts_dir_path( file
)))
2927 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2928 HeapFree(GetProcessHeap(), 0, unixname
);
2930 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2931 if (!ret
&& (unixname
= get_data_dir_path( file
)))
2933 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2934 HeapFree(GetProcessHeap(), 0, unixname
);
2938 LeaveCriticalSection( &freetype_cs
);
2943 /*************************************************************
2944 * WineEngAddFontMemResourceEx
2947 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2951 if (ft_handle
) /* do it only if we have freetype up and running */
2953 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2955 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2956 memcpy(pFontCopy
, pbFont
, cbFont
);
2958 EnterCriticalSection( &freetype_cs
);
2959 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2960 LeaveCriticalSection( &freetype_cs
);
2964 TRACE("AddFontToList failed\n");
2965 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2968 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2969 * For now return something unique but quite random
2971 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2972 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2979 /*************************************************************
2980 * WineEngRemoveFontResourceEx
2983 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2989 if (ft_handle
) /* do it only if we have freetype up and running */
2993 EnterCriticalSection( &freetype_cs
);
2995 if ((unixname
= wine_get_unix_file_name(file
)))
2997 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2999 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3000 ret
= remove_font_resource( unixname
, addfont_flags
);
3001 HeapFree(GetProcessHeap(), 0, unixname
);
3003 if (!ret
&& !strchrW(file
, '\\'))
3005 if ((unixname
= get_winfonts_dir_path( file
)))
3007 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3008 HeapFree(GetProcessHeap(), 0, unixname
);
3010 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3012 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3013 HeapFree(GetProcessHeap(), 0, unixname
);
3017 LeaveCriticalSection( &freetype_cs
);
3022 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3028 if (!font_file
) return NULL
;
3030 file_len
= strlenW( font_file
);
3032 if (font_path
&& font_path
[0])
3034 int path_len
= strlenW( font_path
);
3035 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3036 if (!fullname
) return NULL
;
3037 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3038 fullname
[path_len
] = '\\';
3039 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3043 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3044 if (!len
) return NULL
;
3045 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3046 if (!fullname
) return NULL
;
3047 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3050 unix_name
= wine_get_unix_file_name( fullname
);
3051 HeapFree( GetProcessHeap(), 0, fullname
);
3055 #include <pshpack1.h>
3058 WORD num_of_resources
;
3062 CHAR dfCopyright
[60];
3068 WORD dfInternalLeading
;
3069 WORD dfExternalLeading
;
3077 BYTE dfPitchAndFamily
;
3088 CHAR szFaceName
[LF_FACESIZE
];
3091 #include <poppack.h>
3093 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3094 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3096 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3098 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3100 WCHAR
*name
, *english_name
;
3102 NEWTEXTMETRICEXW ntm
;
3105 if (!ft_face
) return FALSE
;
3106 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3107 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3108 pFT_Done_Face( ft_face
);
3110 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3111 release_face( face
);
3112 HeapFree( GetProcessHeap(), 0, name
);
3113 HeapFree( GetProcessHeap(), 0, english_name
);
3115 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3117 memset( fd
, 0, sizeof(*fd
) );
3119 fd
->num_of_resources
= 1;
3121 fd
->dfVersion
= 0x200;
3122 fd
->dfSize
= sizeof(*fd
);
3123 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3124 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3125 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3127 fd
->dfHorizRes
= 72;
3128 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3129 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3130 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3131 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3132 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3133 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3134 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3135 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3137 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3138 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3139 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3140 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3141 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3142 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3143 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3144 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3145 fd
->dfWidthBytes
= 0;
3147 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3149 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3154 #define NE_FFLAGS_LIBMODULE 0x8000
3155 #define NE_OSFLAGS_WINDOWS 0x02
3157 static const char dos_string
[0x40] = "This is a TrueType resource file";
3158 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3160 #include <pshpack2.h>
3181 struct ne_typeinfo fontdir_type
;
3182 struct ne_nameinfo fontdir_name
;
3183 struct ne_typeinfo scalable_type
;
3184 struct ne_nameinfo scalable_name
;
3186 BYTE fontdir_res_name
[8];
3189 #include <poppack.h>
3191 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3195 DWORD size
, written
;
3197 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3198 char *font_fileA
, *last_part
, *ext
;
3199 IMAGE_DOS_HEADER dos
;
3200 IMAGE_OS2_HEADER ne
=
3202 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3204 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3205 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3207 struct rsrc_tab rsrc_tab
=
3211 { 0, 0, 0x0c50, 0x2c, 0 },
3213 { 0, 0, 0x0c50, 0x8001, 0 },
3215 { 7,'F','O','N','T','D','I','R'}
3218 memset( &dos
, 0, sizeof(dos
) );
3219 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3220 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3222 /* import name is last part\0, resident name is last part without extension
3223 non-resident name is "FONTRES:" + lfFaceName */
3225 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3226 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3227 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3229 last_part
= strrchr( font_fileA
, '\\' );
3230 if (last_part
) last_part
++;
3231 else last_part
= font_fileA
;
3232 import_name_len
= strlen( last_part
) + 1;
3234 ext
= strchr( last_part
, '.' );
3235 if (ext
) res_name_len
= ext
- last_part
;
3236 else res_name_len
= import_name_len
- 1;
3238 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3240 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3241 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3242 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3243 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3245 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3247 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3248 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3249 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3250 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3252 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3253 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3257 HeapFree( GetProcessHeap(), 0, font_fileA
);
3261 memcpy( ptr
, &dos
, sizeof(dos
) );
3262 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3263 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3265 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3266 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3268 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3269 *ptr
++ = res_name_len
;
3270 memcpy( ptr
, last_part
, res_name_len
);
3272 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3273 *ptr
++ = import_name_len
;
3274 memcpy( ptr
, last_part
, import_name_len
);
3276 ptr
= start
+ ne
.ne_nrestab
;
3277 *ptr
++ = non_res_name_len
;
3278 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3279 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3281 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3282 memcpy( ptr
, font_fileA
, font_file_len
);
3284 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3285 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3287 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3288 if (file
!= INVALID_HANDLE_VALUE
)
3290 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3292 CloseHandle( file
);
3295 HeapFree( GetProcessHeap(), 0, start
);
3296 HeapFree( GetProcessHeap(), 0, font_fileA
);
3301 /*************************************************************
3302 * WineEngCreateScalableFontResource
3305 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3306 LPCWSTR font_file
, LPCWSTR font_path
)
3308 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3309 struct fontdir fontdir
;
3312 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3313 SetLastError( ERROR_INVALID_PARAMETER
);
3316 if (hidden
) fontdir
.dfType
|= 0x80;
3317 ret
= create_fot( resource
, font_file
, &fontdir
);
3320 HeapFree( GetProcessHeap(), 0, unix_name
);
3324 static const struct nls_update_font_list
3326 UINT ansi_cp
, oem_cp
;
3327 const char *oem
, *fixed
, *system
;
3328 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3329 /* these are for font substitutes */
3330 const char *shelldlg
, *tmsrmn
;
3331 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3335 const char *from
, *to
;
3336 } arial_0
, courier_new_0
, times_new_roman_0
;
3337 } nls_update_font_list
[] =
3339 /* Latin 1 (United States) */
3340 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3341 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3342 "Tahoma","Times New Roman",
3343 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3346 /* Latin 1 (Multilingual) */
3347 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3348 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3349 "Tahoma","Times New Roman", /* FIXME unverified */
3350 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3353 /* Eastern Europe */
3354 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3355 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3356 "Tahoma","Times New Roman", /* FIXME unverified */
3357 "Fixedsys,238", "System,238",
3358 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3359 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3360 { "Arial CE,0", "Arial,238" },
3361 { "Courier New CE,0", "Courier New,238" },
3362 { "Times New Roman CE,0", "Times New Roman,238" }
3365 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3366 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3367 "Tahoma","Times New Roman", /* FIXME unverified */
3368 "Fixedsys,204", "System,204",
3369 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3370 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3371 { "Arial Cyr,0", "Arial,204" },
3372 { "Courier New Cyr,0", "Courier New,204" },
3373 { "Times New Roman Cyr,0", "Times New Roman,204" }
3376 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3377 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3378 "Tahoma","Times New Roman", /* FIXME unverified */
3379 "Fixedsys,161", "System,161",
3380 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3381 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3382 { "Arial Greek,0", "Arial,161" },
3383 { "Courier New Greek,0", "Courier New,161" },
3384 { "Times New Roman Greek,0", "Times New Roman,161" }
3387 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3388 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3389 "Tahoma","Times New Roman", /* FIXME unverified */
3390 "Fixedsys,162", "System,162",
3391 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3392 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3393 { "Arial Tur,0", "Arial,162" },
3394 { "Courier New Tur,0", "Courier New,162" },
3395 { "Times New Roman Tur,0", "Times New Roman,162" }
3398 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3399 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3400 "Tahoma","Times New Roman", /* FIXME unverified */
3401 "Fixedsys,177", "System,177",
3402 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3403 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3407 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3408 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3409 "Tahoma","Times New Roman", /* FIXME unverified */
3410 "Fixedsys,178", "System,178",
3411 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3412 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3416 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3417 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3418 "Tahoma","Times New Roman", /* FIXME unverified */
3419 "Fixedsys,186", "System,186",
3420 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3421 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3422 { "Arial Baltic,0", "Arial,186" },
3423 { "Courier New Baltic,0", "Courier New,186" },
3424 { "Times New Roman Baltic,0", "Times New Roman,186" }
3427 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3428 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3429 "Tahoma","Times New Roman", /* FIXME unverified */
3430 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3434 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3435 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3436 "Tahoma","Times New Roman", /* FIXME unverified */
3437 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3441 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3442 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3443 "MS UI Gothic","MS Serif",
3444 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3447 /* Chinese Simplified */
3448 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3449 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3450 "SimSun", "NSimSun",
3451 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3455 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3456 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3458 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3461 /* Chinese Traditional */
3462 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3463 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3464 "PMingLiU", "MingLiU",
3465 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3470 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3472 return ( ansi_cp
== 932 /* CP932 for Japanese */
3473 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3474 || ansi_cp
== 949 /* CP949 for Korean */
3475 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3478 static inline HKEY
create_fonts_NT_registry_key(void)
3482 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3483 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3487 static inline HKEY
create_fonts_9x_registry_key(void)
3491 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3492 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3496 static inline HKEY
create_config_fonts_registry_key(void)
3500 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3501 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3505 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3507 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3509 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3510 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3511 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3512 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3515 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3518 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3520 RegDeleteValueA(hkey
, name
);
3523 static void update_font_association_info(UINT current_ansi_codepage
)
3525 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3526 static const char *assoc_charset_subkey
= "Associated Charset";
3528 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3531 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3534 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3536 switch (current_ansi_codepage
)
3539 set_value_key(hsubkey
, "ANSI(00)", "NO");
3540 set_value_key(hsubkey
, "OEM(FF)", "NO");
3541 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3546 set_value_key(hsubkey
, "ANSI(00)", "YES");
3547 set_value_key(hsubkey
, "OEM(FF)", "YES");
3548 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3551 RegCloseKey(hsubkey
);
3554 /* TODO: Associated DefaultFonts */
3560 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3563 static void update_font_info(void)
3565 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3566 char buf
[40], cpbuf
[40];
3569 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3570 DWORD screen_dpi
= 96, font_dpi
= 0;
3573 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3574 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3575 &hkey
) == ERROR_SUCCESS
)
3577 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3581 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3584 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3586 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3587 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3588 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3589 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3590 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3592 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3593 if (is_dbcs_ansi_cp(ansi_cp
))
3594 use_default_fallback
= TRUE
;
3598 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3600 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3605 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3606 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3608 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3609 ansi_cp
, oem_cp
, screen_dpi
);
3611 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3612 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3615 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3619 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3620 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3622 hkey
= create_config_fonts_registry_key();
3623 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3624 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3625 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3628 hkey
= create_fonts_NT_registry_key();
3629 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3632 hkey
= create_fonts_9x_registry_key();
3633 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3636 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3638 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3639 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3640 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3641 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3643 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3644 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3645 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3646 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3647 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3648 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3649 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3650 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3652 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3653 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3654 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3662 /* Delete the FontSubstitutes from other locales */
3663 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3665 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3666 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3667 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3673 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3675 /* update locale dependent font association info in registry.
3676 update only when codepages changed, not logpixels. */
3677 if (strcmp(buf
, cpbuf
) != 0)
3678 update_font_association_info(ansi_cp
);
3681 static BOOL
init_freetype(void)
3683 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3686 "Wine cannot find the FreeType font library. To enable Wine to\n"
3687 "use TrueType fonts please install a version of FreeType greater than\n"
3688 "or equal to 2.0.5.\n"
3689 "http://www.freetype.org\n");
3693 #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;}
3695 LOAD_FUNCPTR(FT_Done_Face
)
3696 LOAD_FUNCPTR(FT_Get_Char_Index
)
3697 LOAD_FUNCPTR(FT_Get_First_Char
)
3698 LOAD_FUNCPTR(FT_Get_Module
)
3699 LOAD_FUNCPTR(FT_Get_Next_Char
)
3700 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3701 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3702 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3703 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3704 LOAD_FUNCPTR(FT_Init_FreeType
)
3705 LOAD_FUNCPTR(FT_Library_Version
)
3706 LOAD_FUNCPTR(FT_Load_Glyph
)
3707 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3708 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3709 #ifndef FT_MULFIX_INLINED
3710 LOAD_FUNCPTR(FT_MulFix
)
3712 LOAD_FUNCPTR(FT_New_Face
)
3713 LOAD_FUNCPTR(FT_New_Memory_Face
)
3714 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3715 LOAD_FUNCPTR(FT_Outline_Transform
)
3716 LOAD_FUNCPTR(FT_Outline_Translate
)
3717 LOAD_FUNCPTR(FT_Render_Glyph
)
3718 LOAD_FUNCPTR(FT_Select_Charmap
)
3719 LOAD_FUNCPTR(FT_Set_Charmap
)
3720 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3721 LOAD_FUNCPTR(FT_Vector_Transform
)
3722 LOAD_FUNCPTR(FT_Vector_Unit
)
3724 /* Don't warn if these ones are missing */
3725 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3726 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3727 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3730 if(pFT_Init_FreeType(&library
) != 0) {
3731 ERR("Can't init FreeType library\n");
3732 wine_dlclose(ft_handle
, NULL
, 0);
3736 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3738 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3739 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3740 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3741 ((FT_Version
.patch
) & 0x0000ff);
3743 font_driver
= &freetype_funcs
;
3748 "Wine cannot find certain functions that it needs inside the FreeType\n"
3749 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3750 "FreeType to at least version 2.1.4.\n"
3751 "http://www.freetype.org\n");
3752 wine_dlclose(ft_handle
, NULL
, 0);
3757 static void init_font_list(void)
3759 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3760 static const WCHAR pathW
[] = {'P','a','t','h',0};
3762 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3763 WCHAR windowsdir
[MAX_PATH
];
3765 const char *data_dir
;
3767 delete_external_font_keys();
3769 /* load the system bitmap fonts */
3770 load_system_fonts();
3772 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3773 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3774 strcatW(windowsdir
, fontsW
);
3775 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3777 ReadFontDir(unixname
, FALSE
);
3778 HeapFree(GetProcessHeap(), 0, unixname
);
3781 /* load the system truetype fonts */
3782 data_dir
= wine_get_data_dir();
3783 if (!data_dir
) data_dir
= wine_get_build_dir();
3784 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3786 strcpy(unixname
, data_dir
);
3787 strcat(unixname
, "/fonts/");
3788 ReadFontDir(unixname
, TRUE
);
3789 HeapFree(GetProcessHeap(), 0, unixname
);
3792 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3793 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3794 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3796 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3797 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3798 &hkey
) == ERROR_SUCCESS
)
3800 LPWSTR data
, valueW
;
3801 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3802 &valuelen
, &datalen
, NULL
, NULL
);
3804 valuelen
++; /* returned value doesn't include room for '\0' */
3805 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3806 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3809 dlen
= datalen
* sizeof(WCHAR
);
3811 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3812 &dlen
) == ERROR_SUCCESS
)
3814 if(data
[0] && (data
[1] == ':'))
3816 if((unixname
= wine_get_unix_file_name(data
)))
3818 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3819 HeapFree(GetProcessHeap(), 0, unixname
);
3822 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3824 WCHAR pathW
[MAX_PATH
];
3825 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3828 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3829 if((unixname
= wine_get_unix_file_name(pathW
)))
3831 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3832 HeapFree(GetProcessHeap(), 0, unixname
);
3835 load_font_from_data_dir(data
);
3837 /* reset dlen and vlen */
3842 HeapFree(GetProcessHeap(), 0, data
);
3843 HeapFree(GetProcessHeap(), 0, valueW
);
3847 #ifdef SONAME_LIBFONTCONFIG
3848 load_fontconfig_fonts();
3849 #elif defined(HAVE_CARBON_CARBON_H)
3853 /* then look in any directories that we've specified in the config file */
3854 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3855 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3861 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3863 len
+= sizeof(WCHAR
);
3864 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3865 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3867 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3868 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3869 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3870 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3875 LPSTR next
= strchr( ptr
, ':' );
3876 if (next
) *next
++ = 0;
3877 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3878 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3880 strcpy( unixname
, home
);
3881 strcat( unixname
, ptr
+ 1 );
3882 ReadFontDir( unixname
, TRUE
);
3883 HeapFree( GetProcessHeap(), 0, unixname
);
3886 ReadFontDir( ptr
, TRUE
);
3889 HeapFree( GetProcessHeap(), 0, valueA
);
3891 HeapFree( GetProcessHeap(), 0, valueW
);
3897 static BOOL
move_to_front(const WCHAR
*name
)
3899 Family
*family
, *cursor2
;
3900 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3902 if(!strcmpiW(family
->FamilyName
, name
))
3904 list_remove(&family
->entry
);
3905 list_add_head(&font_list
, &family
->entry
);
3912 static BOOL
set_default(const WCHAR
**name_list
)
3916 if (move_to_front(*name_list
)) return TRUE
;
3923 static void reorder_font_list(void)
3925 set_default( default_serif_list
);
3926 set_default( default_fixed_list
);
3927 set_default( default_sans_list
);
3930 /*************************************************************
3933 * Initialize FreeType library and create a list of available faces
3935 BOOL
WineEngInit(void)
3940 /* update locale dependent font info in registry */
3943 if(!init_freetype()) return FALSE
;
3945 #ifdef SONAME_LIBFONTCONFIG
3949 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3951 ERR("Failed to create font mutex\n");
3954 WaitForSingleObject(font_mutex
, INFINITE
);
3956 create_font_cache_key(&hkey_font_cache
, &disposition
);
3958 if(disposition
== REG_CREATED_NEW_KEY
)
3961 load_font_list_from_cache(hkey_font_cache
);
3963 reorder_font_list();
3970 if(disposition
== REG_CREATED_NEW_KEY
)
3971 update_reg_entries();
3973 init_system_links();
3975 ReleaseMutex(font_mutex
);
3980 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3983 TT_HoriHeader
*pHori
;
3986 const LONG MAX_PPEM
= (1 << 16) - 1;
3988 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3989 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3991 if(height
== 0) height
= 16;
3993 /* Calc. height of EM square:
3995 * For +ve lfHeight we have
3996 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3997 * Re-arranging gives:
3998 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4000 * For -ve lfHeight we have
4002 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4003 * with il = winAscent + winDescent - units_per_em]
4008 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
4009 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4010 pHori
->Ascender
- pHori
->Descender
);
4012 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4013 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
4014 if(ppem
> MAX_PPEM
) {
4015 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4019 else if(height
>= -MAX_PPEM
)
4022 WARN("Ignoring too large height %d\n", height
);
4029 static struct font_mapping
*map_font_file( const char *name
)
4031 struct font_mapping
*mapping
;
4035 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4036 if (fstat( fd
, &st
) == -1) goto error
;
4038 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4040 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4042 mapping
->refcount
++;
4047 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4050 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4053 if (mapping
->data
== MAP_FAILED
)
4055 HeapFree( GetProcessHeap(), 0, mapping
);
4058 mapping
->refcount
= 1;
4059 mapping
->dev
= st
.st_dev
;
4060 mapping
->ino
= st
.st_ino
;
4061 mapping
->size
= st
.st_size
;
4062 list_add_tail( &mappings_list
, &mapping
->entry
);
4070 static void unmap_font_file( struct font_mapping
*mapping
)
4072 if (!--mapping
->refcount
)
4074 list_remove( &mapping
->entry
);
4075 munmap( mapping
->data
, mapping
->size
);
4076 HeapFree( GetProcessHeap(), 0, mapping
);
4080 static LONG
load_VDMX(GdiFont
*, LONG
);
4082 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4089 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4093 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4094 font
->mapping
= map_font_file( filename
);
4095 HeapFree( GetProcessHeap(), 0, filename
);
4098 WARN("failed to map %s\n", debugstr_w(face
->file
));
4101 data_ptr
= font
->mapping
->data
;
4102 data_size
= font
->mapping
->size
;
4106 data_ptr
= face
->font_data_ptr
;
4107 data_size
= face
->font_data_size
;
4110 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4112 ERR("FT_New_Face rets %d\n", err
);
4116 /* set it here, as load_VDMX needs it */
4117 font
->ft_face
= ft_face
;
4119 if(FT_IS_SCALABLE(ft_face
)) {
4120 /* load the VDMX table if we have one */
4121 font
->ppem
= load_VDMX(font
, height
);
4123 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4124 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4126 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4127 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4129 font
->ppem
= height
;
4130 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4131 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4137 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4139 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4140 a single face with the requested charset. The idea is to check if
4141 the selected font supports the current ANSI codepage, if it does
4142 return the corresponding charset, else return the first charset */
4145 int acp
= GetACP(), i
;
4149 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4151 const SYSTEM_LINKS
*font_link
;
4153 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4154 return csi
.ciCharset
;
4156 font_link
= find_font_link(family_name
);
4157 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4158 return csi
.ciCharset
;
4161 for(i
= 0; i
< 32; i
++) {
4163 if(face
->fs
.fsCsb
[0] & fs0
) {
4164 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4166 return csi
.ciCharset
;
4169 FIXME("TCI failing on %x\n", fs0
);
4173 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4174 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4176 return DEFAULT_CHARSET
;
4179 static GdiFont
*alloc_font(void)
4181 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4184 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4185 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4187 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4188 ret
->total_kern_pairs
= (DWORD
)-1;
4189 ret
->kern_pairs
= NULL
;
4190 list_init(&ret
->child_fonts
);
4194 static void free_font(GdiFont
*font
)
4196 CHILD_FONT
*child
, *child_next
;
4199 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4201 list_remove(&child
->entry
);
4203 free_font(child
->font
);
4204 release_face( child
->face
);
4205 HeapFree(GetProcessHeap(), 0, child
);
4208 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4209 if (font
->mapping
) unmap_font_file( font
->mapping
);
4210 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4211 HeapFree(GetProcessHeap(), 0, font
->potm
);
4212 HeapFree(GetProcessHeap(), 0, font
->name
);
4213 for (i
= 0; i
< font
->gmsize
; i
++)
4214 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4215 HeapFree(GetProcessHeap(), 0, font
->gm
);
4216 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4217 HeapFree(GetProcessHeap(), 0, font
);
4221 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4223 FT_Face ft_face
= font
->ft_face
;
4227 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4234 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4236 /* make sure value of len is the value freetype says it needs */
4239 FT_ULong needed
= 0;
4240 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4241 if( !err
&& needed
< len
) len
= needed
;
4243 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4246 TRACE("Can't find table %c%c%c%c\n",
4247 /* bytes were reversed */
4248 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4249 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4255 /*************************************************************
4258 * load the vdmx entry for the specified height
4261 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4262 ( ( (FT_ULong)_x4 << 24 ) | \
4263 ( (FT_ULong)_x3 << 16 ) | \
4264 ( (FT_ULong)_x2 << 8 ) | \
4267 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4282 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4286 BYTE devXRatio
, devYRatio
;
4287 USHORT numRecs
, numRatios
;
4288 DWORD result
, offset
= -1;
4292 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4294 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4297 /* FIXME: need the real device aspect ratio */
4301 numRecs
= GET_BE_WORD(hdr
[1]);
4302 numRatios
= GET_BE_WORD(hdr
[2]);
4304 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4305 for(i
= 0; i
< numRatios
; i
++) {
4308 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4309 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4312 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4314 if((ratio
.xRatio
== 0 &&
4315 ratio
.yStartRatio
== 0 &&
4316 ratio
.yEndRatio
== 0) ||
4317 (devXRatio
== ratio
.xRatio
&&
4318 devYRatio
>= ratio
.yStartRatio
&&
4319 devYRatio
<= ratio
.yEndRatio
))
4321 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4322 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4323 offset
= GET_BE_WORD(tmp
);
4329 FIXME("No suitable ratio found\n");
4333 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4335 BYTE startsz
, endsz
;
4338 recs
= GET_BE_WORD(group
.recs
);
4339 startsz
= group
.startsz
;
4340 endsz
= group
.endsz
;
4342 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4344 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4345 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4346 if(result
== GDI_ERROR
) {
4347 FIXME("Failed to retrieve vTable\n");
4352 for(i
= 0; i
< recs
; i
++) {
4353 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4354 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4355 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4357 if(yMax
+ -yMin
== height
) {
4360 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4363 if(yMax
+ -yMin
> height
) {
4366 goto end
; /* failed */
4368 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4369 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4370 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4371 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4377 TRACE("ppem not found for height %d\n", height
);
4381 HeapFree(GetProcessHeap(), 0, vTable
);
4387 static void dump_gdi_font_list(void)
4391 TRACE("---------- Font Cache ----------\n");
4392 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4393 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4394 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4397 static void grab_font( GdiFont
*font
)
4399 if (!font
->refcount
++)
4401 list_remove( &font
->unused_entry
);
4402 unused_font_count
--;
4406 static void release_font( GdiFont
*font
)
4409 if (!--font
->refcount
)
4411 TRACE( "font %p\n", font
);
4413 /* add it to the unused list */
4414 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4415 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4417 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4418 TRACE( "freeing %p\n", font
);
4419 list_remove( &font
->entry
);
4420 list_remove( &font
->unused_entry
);
4423 else unused_font_count
++;
4425 if (TRACE_ON(font
)) dump_gdi_font_list();
4429 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4431 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4432 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4433 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4434 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4435 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4438 static void calc_hash(FONT_DESC
*pfd
)
4440 DWORD hash
= 0, *ptr
, two_chars
;
4444 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4446 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4448 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4450 pwc
= (WCHAR
*)&two_chars
;
4452 *pwc
= toupperW(*pwc
);
4454 *pwc
= toupperW(*pwc
);
4458 hash
^= !pfd
->can_use_bitmap
;
4463 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4470 fd
.can_use_bitmap
= can_use_bitmap
;
4473 /* try the in-use list */
4474 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4476 if(fontcmp(ret
, &fd
)) continue;
4477 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4478 list_remove( &ret
->entry
);
4479 list_add_head( &gdi_font_list
, &ret
->entry
);
4486 static void add_to_cache(GdiFont
*font
)
4488 static DWORD cache_num
= 1;
4490 font
->cache_num
= cache_num
++;
4491 list_add_head(&gdi_font_list
, &font
->entry
);
4492 TRACE( "font %p\n", font
);
4495 /*************************************************************
4496 * create_child_font_list
4498 static BOOL
create_child_font_list(GdiFont
*font
)
4501 SYSTEM_LINKS
*font_link
;
4502 CHILD_FONT
*font_link_entry
, *new_child
;
4506 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4507 font_name
= psub
? psub
->to
.name
: font
->name
;
4508 font_link
= find_font_link(font_name
);
4509 if (font_link
!= NULL
)
4511 TRACE("found entry in system list\n");
4512 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4514 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4515 new_child
->face
= font_link_entry
->face
;
4516 new_child
->font
= NULL
;
4517 new_child
->face
->refcount
++;
4518 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4519 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4524 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4525 * Sans Serif. This is how asian windows get default fallbacks for fonts
4527 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4528 font
->charset
!= OEM_CHARSET
&&
4529 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4531 font_link
= find_font_link(szDefaultFallbackLink
);
4532 if (font_link
!= NULL
)
4534 TRACE("found entry in default fallback list\n");
4535 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4537 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4538 new_child
->face
= font_link_entry
->face
;
4539 new_child
->font
= NULL
;
4540 new_child
->face
->refcount
++;
4541 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4542 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4551 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4553 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4555 if (pFT_Set_Charmap
)
4558 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4560 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4562 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4564 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4566 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4567 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4569 switch (ft_face
->charmaps
[i
]->platform_id
)
4572 cmap_def
= ft_face
->charmaps
[i
];
4574 case 0: /* Apple Unicode */
4575 cmap0
= ft_face
->charmaps
[i
];
4577 case 1: /* Macintosh */
4578 cmap1
= ft_face
->charmaps
[i
];
4581 cmap2
= ft_face
->charmaps
[i
];
4583 case 3: /* Microsoft */
4584 cmap3
= ft_face
->charmaps
[i
];
4589 if (cmap3
) /* prefer Microsoft cmap table */
4590 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4592 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4594 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4596 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4598 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4600 return ft_err
== FT_Err_Ok
;
4603 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4607 /*************************************************************
4610 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4611 LPCWSTR output
, const DEVMODEW
*devmode
)
4613 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4615 if (!physdev
) return FALSE
;
4616 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4621 /*************************************************************
4624 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4626 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4627 release_font( physdev
->font
);
4628 HeapFree( GetProcessHeap(), 0, physdev
);
4632 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4634 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4635 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4636 const FT_Encoding
*encs
= regular_order
;
4638 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4642 if (select_charmap( face
, *encs
)) break;
4648 #define GASP_GRIDFIT 0x01
4649 #define GASP_DOGRAY 0x02
4650 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4652 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4655 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4656 WORD
*alloced
= NULL
, *ptr
= buf
;
4657 WORD num_recs
, version
;
4661 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4662 if (size
== GDI_ERROR
) return FALSE
;
4663 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4664 if (size
> sizeof(buf
))
4666 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4667 if (!ptr
) return FALSE
;
4670 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4672 version
= GET_BE_WORD( *ptr
++ );
4673 num_recs
= GET_BE_WORD( *ptr
++ );
4675 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4677 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4683 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4684 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4687 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4691 HeapFree( GetProcessHeap(), 0, alloced
);
4695 /*************************************************************
4696 * freetype_SelectFont
4698 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4700 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4702 Face
*face
, *best
, *best_bitmap
;
4703 Family
*family
, *last_resort_family
;
4704 const struct list
*face_list
;
4705 INT height
, width
= 0;
4706 unsigned int score
= 0, new_score
;
4707 signed int diff
= 0, newdiff
;
4708 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4712 FontSubst
*psub
= NULL
;
4713 DC
*dc
= get_dc_ptr( dev
->hdc
);
4714 const SYSTEM_LINKS
*font_link
;
4716 if (!hfont
) /* notification that the font has been changed by another driver */
4718 release_font( physdev
->font
);
4719 physdev
->font
= NULL
;
4720 release_dc_ptr( dc
);
4724 GetObjectW( hfont
, sizeof(lf
), &lf
);
4725 lf
.lfWidth
= abs(lf
.lfWidth
);
4727 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4729 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4730 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4731 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4734 if(dc
->GraphicsMode
== GM_ADVANCED
)
4736 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4737 /* Try to avoid not necessary glyph transformations */
4738 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4740 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4741 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4742 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4747 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4748 font scaling abilities. */
4749 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4750 dcmat
.eM21
= dcmat
.eM12
= 0;
4751 lf
.lfOrientation
= lf
.lfEscapement
;
4752 if (dc
->vport2WorldValid
)
4754 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4755 lf
.lfOrientation
= -lf
.lfOrientation
;
4756 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4757 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4761 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4762 dcmat
.eM21
, dcmat
.eM22
);
4765 EnterCriticalSection( &freetype_cs
);
4767 /* check the cache first */
4768 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4769 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4773 TRACE("not in cache\n");
4776 ret
->font_desc
.matrix
= dcmat
;
4777 ret
->font_desc
.lf
= lf
;
4778 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4779 calc_hash(&ret
->font_desc
);
4781 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4782 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4783 original value lfCharSet. Note this is a special case for
4784 Symbol and doesn't happen at least for "Wingdings*" */
4786 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4787 lf
.lfCharSet
= SYMBOL_CHARSET
;
4789 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4790 switch(lf
.lfCharSet
) {
4791 case DEFAULT_CHARSET
:
4792 csi
.fs
.fsCsb
[0] = 0;
4795 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4796 csi
.fs
.fsCsb
[0] = 0;
4802 if(lf
.lfFaceName
[0] != '\0') {
4803 CHILD_FONT
*font_link_entry
;
4804 LPWSTR FaceName
= lf
.lfFaceName
;
4806 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4809 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4810 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4811 if (psub
->to
.charset
!= -1)
4812 lf
.lfCharSet
= psub
->to
.charset
;
4815 /* We want a match on name and charset or just name if
4816 charset was DEFAULT_CHARSET. If the latter then
4817 we fixup the returned charset later in get_nearest_charset
4818 where we'll either use the charset of the current ansi codepage
4819 or if that's unavailable the first charset that the font supports.
4821 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4822 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4823 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4825 font_link
= find_font_link(family
->FamilyName
);
4826 face_list
= get_face_list_from_family(family
);
4827 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4828 if (!(face
->scalable
|| can_use_bitmap
))
4830 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4832 if (font_link
!= NULL
&&
4833 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4835 if (!csi
.fs
.fsCsb
[0])
4841 /* Search by full face name. */
4842 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4843 face_list
= get_face_list_from_family(family
);
4844 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4845 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4846 (face
->scalable
|| can_use_bitmap
))
4848 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4850 font_link
= find_font_link(family
->FamilyName
);
4851 if (font_link
!= NULL
&&
4852 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4859 * Try check the SystemLink list first for a replacement font.
4860 * We may find good replacements there.
4862 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4864 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4865 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4867 TRACE("found entry in system list\n");
4868 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4870 const SYSTEM_LINKS
*links
;
4872 face
= font_link_entry
->face
;
4873 if (!(face
->scalable
|| can_use_bitmap
))
4875 family
= face
->family
;
4876 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4878 links
= find_font_link(family
->FamilyName
);
4879 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4886 psub
= NULL
; /* substitution is no more relevant */
4888 /* If requested charset was DEFAULT_CHARSET then try using charset
4889 corresponding to the current ansi codepage */
4890 if (!csi
.fs
.fsCsb
[0])
4893 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4894 FIXME("TCI failed on codepage %d\n", acp
);
4895 csi
.fs
.fsCsb
[0] = 0;
4897 lf
.lfCharSet
= csi
.ciCharset
;
4900 want_vertical
= (lf
.lfFaceName
[0] == '@');
4902 /* Face families are in the top 4 bits of lfPitchAndFamily,
4903 so mask with 0xF0 before testing */
4905 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4906 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4907 strcpyW(lf
.lfFaceName
, defFixed
);
4908 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4909 strcpyW(lf
.lfFaceName
, defSerif
);
4910 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4911 strcpyW(lf
.lfFaceName
, defSans
);
4913 strcpyW(lf
.lfFaceName
, defSans
);
4914 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4915 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4916 font_link
= find_font_link(family
->FamilyName
);
4917 face_list
= get_face_list_from_family(family
);
4918 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4919 if (!(face
->scalable
|| can_use_bitmap
))
4921 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4923 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4929 last_resort_family
= NULL
;
4930 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4931 font_link
= find_font_link(family
->FamilyName
);
4932 face_list
= get_face_list_from_family(family
);
4933 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4934 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
4935 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4936 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4939 if(can_use_bitmap
&& !last_resort_family
)
4940 last_resort_family
= family
;
4945 if(last_resort_family
) {
4946 family
= last_resort_family
;
4947 csi
.fs
.fsCsb
[0] = 0;
4951 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4952 face_list
= get_face_list_from_family(family
);
4953 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4954 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
4955 csi
.fs
.fsCsb
[0] = 0;
4956 WARN("just using first face for now\n");
4959 if(can_use_bitmap
&& !last_resort_family
)
4960 last_resort_family
= family
;
4963 if(!last_resort_family
) {
4964 FIXME("can't find a single appropriate font - bailing\n");
4970 WARN("could only find a bitmap font - this will probably look awful!\n");
4971 family
= last_resort_family
;
4972 csi
.fs
.fsCsb
[0] = 0;
4975 it
= lf
.lfItalic
? 1 : 0;
4976 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4978 height
= lf
.lfHeight
;
4980 face
= best
= best_bitmap
= NULL
;
4981 font_link
= find_font_link(family
->FamilyName
);
4982 face_list
= get_face_list_from_family(family
);
4983 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4985 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4986 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4991 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4992 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4993 new_score
= (italic
^ it
) + (bold
^ bd
);
4994 if(!best
|| new_score
<= score
)
4996 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4997 italic
, bold
, it
, bd
);
5000 if(best
->scalable
&& score
== 0) break;
5004 newdiff
= height
- (signed int)(best
->size
.height
);
5006 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5007 if(!best_bitmap
|| new_score
< score
||
5008 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5010 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5013 if(score
== 0 && diff
== 0) break;
5020 face
= best
->scalable
? best
: best_bitmap
;
5021 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5022 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5025 height
= lf
.lfHeight
;
5029 if(csi
.fs
.fsCsb
[0]) {
5030 ret
->charset
= lf
.lfCharSet
;
5031 ret
->codepage
= csi
.ciACP
;
5034 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5036 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5037 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5039 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5041 if(!face
->scalable
) {
5042 /* Windows uses integer scaling factors for bitmap fonts */
5043 INT scale
, scaled_height
;
5044 GdiFont
*cachedfont
;
5046 /* FIXME: rotation of bitmap fonts is ignored */
5047 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5049 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5050 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5051 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5052 /* As we changed the matrix, we need to search the cache for the font again,
5053 * otherwise we might explode the cache. */
5054 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5055 TRACE("Found cached font after non-scalable matrix rescale!\n");
5060 calc_hash(&ret
->font_desc
);
5062 if (height
!= 0) height
= diff
;
5063 height
+= face
->size
.height
;
5065 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5066 scaled_height
= scale
* face
->size
.height
;
5067 /* Only jump to the next height if the difference <= 25% original height */
5068 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5069 /* The jump between unscaled and doubled is delayed by 1 */
5070 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5071 ret
->scale_y
= scale
;
5073 width
= face
->size
.x_ppem
>> 6;
5074 height
= face
->size
.y_ppem
>> 6;
5078 TRACE("font scale y: %f\n", ret
->scale_y
);
5080 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5089 ret
->ntmFlags
= face
->ntmFlags
;
5091 pick_charmap( ret
->ft_face
, ret
->charset
);
5093 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5094 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5095 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5096 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5097 create_child_font_list(ret
);
5099 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5101 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5102 if (length
!= GDI_ERROR
)
5104 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5105 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5106 TRACE("Loaded GSUB table of %i bytes\n",length
);
5109 ret
->aa_flags
= HIWORD( face
->flags
);
5111 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5117 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5119 switch (lf
.lfQuality
)
5121 case NONANTIALIASED_QUALITY
:
5122 case ANTIALIASED_QUALITY
:
5123 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5125 case CLEARTYPE_QUALITY
:
5126 case CLEARTYPE_NATURAL_QUALITY
:
5128 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5129 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5131 /* fixup the antialiasing flags for that font */
5134 case WINE_GGO_HRGB_BITMAP
:
5135 case WINE_GGO_HBGR_BITMAP
:
5136 case WINE_GGO_VRGB_BITMAP
:
5137 case WINE_GGO_VBGR_BITMAP
:
5138 if (is_subpixel_rendering_enabled()) break;
5139 *aa_flags
= GGO_GRAY4_BITMAP
;
5141 case GGO_GRAY2_BITMAP
:
5142 case GGO_GRAY4_BITMAP
:
5143 case GGO_GRAY8_BITMAP
:
5144 case WINE_GGO_GRAY16_BITMAP
:
5145 if (is_hinting_enabled())
5148 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5150 TRACE( "font %s %d aa disabled by GASP\n",
5151 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5152 *aa_flags
= GGO_BITMAP
;
5157 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5158 release_font( physdev
->font
);
5159 physdev
->font
= ret
;
5161 LeaveCriticalSection( &freetype_cs
);
5162 release_dc_ptr( dc
);
5163 return ret
? hfont
: 0;
5166 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5173 id
+= IDS_FIRST_SCRIPT
;
5174 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5175 if (!rsrc
) return 0;
5176 hMem
= LoadResource( gdi32_module
, rsrc
);
5177 if (!hMem
) return 0;
5179 p
= LockResource( hMem
);
5181 while (id
--) p
+= *p
+ 1;
5183 i
= min(LF_FACESIZE
- 1, *p
);
5184 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5190 /***************************************************
5191 * create_enum_charset_list
5193 * This function creates charset enumeration list because in DEFAULT_CHARSET
5194 * case, the ANSI codepage's charset takes precedence over other charsets.
5195 * This function works as a filter other than DEFAULT_CHARSET case.
5197 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5202 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5203 csi
.fs
.fsCsb
[0] != 0) {
5204 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5205 list
->element
[n
].charset
= csi
.ciCharset
;
5206 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5209 else { /* charset is DEFAULT_CHARSET or invalid. */
5213 /* Set the current codepage's charset as the first element. */
5215 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5216 csi
.fs
.fsCsb
[0] != 0) {
5217 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5218 list
->element
[n
].charset
= csi
.ciCharset
;
5219 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5220 mask
|= csi
.fs
.fsCsb
[0];
5224 /* Fill out left elements. */
5225 for (i
= 0; i
< 32; i
++) {
5227 fs
.fsCsb
[0] = 1L << i
;
5229 if (fs
.fsCsb
[0] & mask
)
5230 continue; /* skip, already added. */
5231 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5232 continue; /* skip, this is an invalid fsCsb bit. */
5234 list
->element
[n
].mask
= fs
.fsCsb
[0];
5235 list
->element
[n
].charset
= csi
.ciCharset
;
5236 load_script_name( i
, list
->element
[n
].name
);
5237 mask
|= fs
.fsCsb
[0];
5241 /* add catch all mask for remaining bits */
5244 list
->element
[n
].mask
= ~mask
;
5245 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5246 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5255 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5256 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5261 if (face
->cached_enum_data
)
5264 *pelf
= face
->cached_enum_data
->elf
;
5265 *pntm
= face
->cached_enum_data
->ntm
;
5266 *ptype
= face
->cached_enum_data
->type
;
5270 font
= alloc_font();
5272 if(face
->scalable
) {
5276 height
= face
->size
.y_ppem
>> 6;
5277 width
= face
->size
.x_ppem
>> 6;
5279 font
->scale_y
= 1.0;
5281 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5287 font
->name
= strdupW( family_name
);
5288 font
->ntmFlags
= face
->ntmFlags
;
5290 if (get_outline_text_metrics(font
))
5292 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5294 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5295 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5296 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5298 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5299 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5301 lstrcpynW(pelf
->elfFullName
,
5302 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5304 lstrcpynW(pelf
->elfStyle
,
5305 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5310 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5312 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5313 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5314 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5316 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5318 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5320 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5321 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5324 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5325 pntm
->ntmFontSig
= face
->fs
;
5327 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5329 pelf
->elfLogFont
.lfEscapement
= 0;
5330 pelf
->elfLogFont
.lfOrientation
= 0;
5331 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5332 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5333 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5334 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5335 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5336 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5337 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5338 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5339 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5340 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5341 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5344 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5345 *ptype
|= TRUETYPE_FONTTYPE
;
5346 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5347 *ptype
|= DEVICE_FONTTYPE
;
5348 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5349 *ptype
|= RASTER_FONTTYPE
;
5351 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5352 if (face
->cached_enum_data
)
5354 face
->cached_enum_data
->elf
= *pelf
;
5355 face
->cached_enum_data
->ntm
= *pntm
;
5356 face
->cached_enum_data
->type
= *ptype
;
5362 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5365 const struct list
*face_list
;
5367 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5369 face_list
= get_face_list_from_family(family
);
5370 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5371 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5376 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5378 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5380 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5383 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5384 FONTENUMPROCW proc
, LPARAM lparam
)
5387 NEWTEXTMETRICEXW ntm
;
5391 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5392 for(i
= 0; i
< list
->total
; i
++) {
5393 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5394 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5395 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5396 i
= list
->total
; /* break out of loop after enumeration */
5400 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5401 /* use the DEFAULT_CHARSET case only if no other charset is present */
5402 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5403 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5404 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5405 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5406 if (!elf
.elfScript
[0])
5407 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5409 /* Font Replacement */
5410 if (family
!= face
->family
)
5412 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5414 strcpyW(elf
.elfFullName
, face
->FullName
);
5416 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5418 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5419 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5420 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5421 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5422 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5423 ntm
.ntmTm
.ntmFlags
);
5424 /* release section before callback (FIXME) */
5425 LeaveCriticalSection( &freetype_cs
);
5426 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5427 EnterCriticalSection( &freetype_cs
);
5432 /*************************************************************
5433 * freetype_EnumFonts
5435 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5439 const struct list
*face_list
;
5441 struct enum_charset_list enum_charsets
;
5445 lf
.lfCharSet
= DEFAULT_CHARSET
;
5446 lf
.lfPitchAndFamily
= 0;
5447 lf
.lfFaceName
[0] = 0;
5451 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5453 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5456 EnterCriticalSection( &freetype_cs
);
5457 if(plf
->lfFaceName
[0]) {
5459 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5462 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5463 debugstr_w(psub
->to
.name
));
5465 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5469 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5470 if (!family_matches(family
, plf
)) continue;
5471 face_list
= get_face_list_from_family(family
);
5472 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5473 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5474 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5478 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5479 face_list
= get_face_list_from_family(family
);
5480 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5481 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5484 LeaveCriticalSection( &freetype_cs
);
5488 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5490 pt
->x
.value
= vec
->x
>> 6;
5491 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5492 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5493 pt
->y
.value
= vec
->y
>> 6;
5494 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5495 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5499 /***************************************************
5500 * According to the MSDN documentation on WideCharToMultiByte,
5501 * certain codepages cannot set the default_used parameter.
5502 * This returns TRUE if the codepage can set that parameter, false else
5503 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5505 static BOOL
codepage_sets_default_used(UINT codepage
)
5519 * GSUB Table handling functions
5522 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5524 const GSUB_CoverageFormat1
* cf1
;
5528 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5530 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5532 TRACE("Coverage Format 1, %i glyphs\n",count
);
5533 for (i
= 0; i
< count
; i
++)
5534 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5538 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5540 const GSUB_CoverageFormat2
* cf2
;
5543 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5545 count
= GET_BE_WORD(cf2
->RangeCount
);
5546 TRACE("Coverage Format 2, %i ranges\n",count
);
5547 for (i
= 0; i
< count
; i
++)
5549 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5551 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5552 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5554 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5555 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5561 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5566 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5568 const GSUB_ScriptList
*script
;
5569 const GSUB_Script
*deflt
= NULL
;
5571 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5573 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5574 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5576 const GSUB_Script
*scr
;
5579 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5580 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5582 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5584 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5590 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5594 const GSUB_LangSys
*Lang
;
5596 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5598 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5600 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5601 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5603 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5606 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5609 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5615 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5618 const GSUB_FeatureList
*feature
;
5619 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5621 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5622 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5624 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5625 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5627 const GSUB_Feature
*feat
;
5628 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5635 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5639 const GSUB_LookupList
*lookup
;
5640 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5642 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5643 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5645 const GSUB_LookupTable
*look
;
5646 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5647 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5648 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5649 if (GET_BE_WORD(look
->LookupType
) != 1)
5650 FIXME("We only handle SubType 1\n");
5655 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5657 const GSUB_SingleSubstFormat1
*ssf1
;
5658 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5659 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5660 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5662 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5663 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5664 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5666 TRACE(" Glyph 0x%x ->",glyph
);
5667 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5668 TRACE(" 0x%x\n",glyph
);
5673 const GSUB_SingleSubstFormat2
*ssf2
;
5677 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5678 offset
= GET_BE_WORD(ssf1
->Coverage
);
5679 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5680 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5681 TRACE(" Coverage index %i\n",index
);
5684 TRACE(" Glyph is 0x%x ->",glyph
);
5685 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5686 TRACE("0x%x\n",glyph
);
5695 static const char* get_opentype_script(const GdiFont
*font
)
5698 * I am not sure if this is the correct way to generate our script tag
5701 switch (font
->charset
)
5703 case ANSI_CHARSET
: return "latn";
5704 case BALTIC_CHARSET
: return "latn"; /* ?? */
5705 case CHINESEBIG5_CHARSET
: return "hani";
5706 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5707 case GB2312_CHARSET
: return "hani";
5708 case GREEK_CHARSET
: return "grek";
5709 case HANGUL_CHARSET
: return "hang";
5710 case RUSSIAN_CHARSET
: return "cyrl";
5711 case SHIFTJIS_CHARSET
: return "kana";
5712 case TURKISH_CHARSET
: return "latn"; /* ?? */
5713 case VIETNAMESE_CHARSET
: return "latn";
5714 case JOHAB_CHARSET
: return "latn"; /* ?? */
5715 case ARABIC_CHARSET
: return "arab";
5716 case HEBREW_CHARSET
: return "hebr";
5717 case THAI_CHARSET
: return "thai";
5718 default: return "latn";
5722 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5724 const GSUB_Header
*header
;
5725 const GSUB_Script
*script
;
5726 const GSUB_LangSys
*language
;
5727 const GSUB_Feature
*feature
;
5729 if (!font
->GSUB_Table
)
5732 header
= font
->GSUB_Table
;
5734 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5737 TRACE("Script not found\n");
5740 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5743 TRACE("Language not found\n");
5746 feature
= GSUB_get_feature(header
, language
, "vrt2");
5748 feature
= GSUB_get_feature(header
, language
, "vert");
5751 TRACE("vrt2/vert feature not found\n");
5754 return GSUB_apply_feature(header
, feature
, glyph
);
5757 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5761 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5762 WCHAR wc
= (WCHAR
)glyph
;
5764 BOOL
*default_used_pointer
;
5767 default_used_pointer
= NULL
;
5768 default_used
= FALSE
;
5769 if (codepage_sets_default_used(font
->codepage
))
5770 default_used_pointer
= &default_used
;
5771 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5773 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
5774 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
5779 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5780 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5784 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5786 if (glyph
< 0x100) glyph
+= 0xf000;
5787 /* there is a number of old pre-Unicode "broken" TTFs, which
5788 do have symbols at U+00XX instead of U+f0XX */
5789 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5790 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5792 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5797 /*************************************************************
5798 * freetype_GetGlyphIndices
5800 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5802 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5805 BOOL got_default
= FALSE
;
5809 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5810 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5813 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5815 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5820 EnterCriticalSection( &freetype_cs
);
5822 for(i
= 0; i
< count
; i
++)
5824 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5829 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5831 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5832 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5837 get_text_metrics(physdev
->font
, &textm
);
5838 default_char
= textm
.tmDefaultChar
;
5842 pgi
[i
] = default_char
;
5845 LeaveCriticalSection( &freetype_cs
);
5849 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5851 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5852 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5855 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5857 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5858 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5861 static inline BYTE
get_max_level( UINT format
)
5865 case GGO_GRAY2_BITMAP
: return 4;
5866 case GGO_GRAY4_BITMAP
: return 16;
5867 case GGO_GRAY8_BITMAP
: return 64;
5872 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5874 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5875 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
5878 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5879 FT_Face ft_face
= incoming_font
->ft_face
;
5880 GdiFont
*font
= incoming_font
;
5881 FT_Glyph_Metrics metrics
;
5882 FT_UInt glyph_index
;
5883 DWORD width
, height
, pitch
, needed
= 0;
5884 FT_Bitmap ft_bitmap
;
5886 INT left
, right
, top
= 0, bottom
= 0, adv
;
5888 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5889 double widthRatio
= 1.0;
5890 FT_Matrix transMat
= identityMat
;
5891 FT_Matrix transMatUnrotated
;
5892 BOOL needsTransform
= FALSE
;
5893 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5894 UINT original_index
;
5895 LONG avgAdvance
= 0;
5898 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5899 buflen
, buf
, lpmat
);
5901 TRACE("font transform %f %f %f %f\n",
5902 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5903 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5905 if(format
& GGO_GLYPH_INDEX
) {
5906 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5907 original_index
= glyph
;
5908 format
&= ~GGO_GLYPH_INDEX
;
5910 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5911 ft_face
= font
->ft_face
;
5912 original_index
= glyph_index
;
5915 if(format
& GGO_UNHINTED
) {
5916 load_flags
|= FT_LOAD_NO_HINTING
;
5917 format
&= ~GGO_UNHINTED
;
5920 /* tategaki never appears to happen to lower glyph index */
5921 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5924 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5925 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5926 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5927 font
->gmsize
* sizeof(GM
*));
5929 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5930 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5932 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5933 *abc
= FONT_GM(font
,original_index
)->abc
;
5934 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5935 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5936 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5937 return 1; /* FIXME */
5941 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5942 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5944 /* Scaling factor */
5949 get_text_metrics(font
, &tm
);
5951 widthRatio
= (double)font
->aveWidth
;
5952 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5955 widthRatio
= font
->scale_y
;
5957 /* Scaling transform */
5958 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5961 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5964 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5966 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5967 needsTransform
= TRUE
;
5970 /* Slant transform */
5971 if (font
->fake_italic
) {
5974 slantMat
.xx
= (1 << 16);
5975 slantMat
.xy
= ((1 << 16) >> 2);
5977 slantMat
.yy
= (1 << 16);
5978 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5979 needsTransform
= TRUE
;
5982 /* Rotation transform */
5983 transMatUnrotated
= transMat
;
5984 if(font
->orientation
&& !tategaki
) {
5985 FT_Matrix rotationMat
;
5987 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5988 pFT_Vector_Unit(&vecAngle
, angle
);
5989 rotationMat
.xx
= vecAngle
.x
;
5990 rotationMat
.xy
= -vecAngle
.y
;
5991 rotationMat
.yx
= -rotationMat
.xy
;
5992 rotationMat
.yy
= rotationMat
.xx
;
5994 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5995 needsTransform
= TRUE
;
5998 /* World transform */
5999 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6002 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6003 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6004 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6005 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6006 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6007 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6008 needsTransform
= TRUE
;
6011 /* Extra transformation specified by caller */
6012 if (!is_identity_MAT2(lpmat
))
6015 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6016 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6017 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6018 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6019 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6020 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6021 needsTransform
= TRUE
;
6024 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6026 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6029 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6033 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6034 * by the text metrics. The proper behavior is to clip the glyph metrics to
6035 * fit within the maximums specified in the text metrics. */
6036 metrics
= ft_face
->glyph
->metrics
;
6037 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6038 get_bitmap_text_metrics(incoming_font
)) {
6039 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6040 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6041 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6042 metrics
.horiBearingY
= top
;
6043 metrics
.height
= top
- bottom
;
6045 /* TODO: Are we supposed to clip the width as well...? */
6046 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6049 if(FT_IS_SCALABLE(incoming_font
->ft_face
)) {
6051 if (get_text_metrics(incoming_font
, &tm
) &&
6052 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6053 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6054 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6056 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6057 TRACE("Fixed-pitch full-width character detected\n");
6059 avgAdvance
= 0; /* cancel this feature */
6063 if(!needsTransform
) {
6064 left
= (INT
)(metrics
.horiBearingX
) & -64;
6065 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6067 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6069 adv
= (INT
)avgAdvance
* 2;
6071 top
= (metrics
.horiBearingY
+ 63) & -64;
6072 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6073 lpgm
->gmCellIncX
= adv
;
6074 lpgm
->gmCellIncY
= 0;
6081 for(xc
= 0; xc
< 2; xc
++) {
6082 for(yc
= 0; yc
< 2; yc
++) {
6083 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6084 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6085 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6086 pFT_Vector_Transform(&vec
, &transMat
);
6087 if(xc
== 0 && yc
== 0) {
6088 left
= right
= vec
.x
;
6089 top
= bottom
= vec
.y
;
6091 if(vec
.x
< left
) left
= vec
.x
;
6092 else if(vec
.x
> right
) right
= vec
.x
;
6093 if(vec
.y
< bottom
) bottom
= vec
.y
;
6094 else if(vec
.y
> top
) top
= vec
.y
;
6099 right
= (right
+ 63) & -64;
6100 bottom
= bottom
& -64;
6101 top
= (top
+ 63) & -64;
6103 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6104 vec
.x
= metrics
.horiAdvance
;
6106 pFT_Vector_Transform(&vec
, &transMat
);
6107 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6108 if (!avgAdvance
|| vec
.y
)
6109 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6111 vec
.x
= incoming_font
->ntmAvgWidth
;
6113 pFT_Vector_Transform(&vec
, &transMat
);
6114 lpgm
->gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6117 vec
.x
= metrics
.horiAdvance
;
6119 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6120 if (!avgAdvance
|| vec
.y
)
6121 adv
= (vec
.x
+63) >> 6;
6123 vec
.x
= incoming_font
->ntmAvgWidth
;
6125 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6126 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6130 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6131 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6132 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
6133 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
6134 abc
->abcA
= left
>> 6;
6135 abc
->abcB
= (right
- left
) >> 6;
6136 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6138 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6139 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6140 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6142 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6143 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6145 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6146 FONT_GM(font
,original_index
)->abc
= *abc
;
6147 FONT_GM(font
,original_index
)->init
= TRUE
;
6150 if(format
== GGO_METRICS
)
6152 return 1; /* FIXME */
6155 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6156 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6158 TRACE("loaded a bitmap\n");
6164 width
= lpgm
->gmBlackBoxX
;
6165 height
= lpgm
->gmBlackBoxY
;
6166 pitch
= ((width
+ 31) >> 5) << 2;
6167 needed
= pitch
* height
;
6169 if(!buf
|| !buflen
) break;
6171 switch(ft_face
->glyph
->format
) {
6172 case ft_glyph_format_bitmap
:
6174 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6175 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6176 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6178 memcpy(dst
, src
, w
);
6179 src
+= ft_face
->glyph
->bitmap
.pitch
;
6185 case ft_glyph_format_outline
:
6186 ft_bitmap
.width
= width
;
6187 ft_bitmap
.rows
= height
;
6188 ft_bitmap
.pitch
= pitch
;
6189 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6190 ft_bitmap
.buffer
= buf
;
6193 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6195 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6197 /* Note: FreeType will only set 'black' bits for us. */
6198 memset(buf
, 0, needed
);
6199 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6203 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6208 case GGO_GRAY2_BITMAP
:
6209 case GGO_GRAY4_BITMAP
:
6210 case GGO_GRAY8_BITMAP
:
6211 case WINE_GGO_GRAY16_BITMAP
:
6213 unsigned int max_level
, row
, col
;
6216 width
= lpgm
->gmBlackBoxX
;
6217 height
= lpgm
->gmBlackBoxY
;
6218 pitch
= (width
+ 3) / 4 * 4;
6219 needed
= pitch
* height
;
6221 if(!buf
|| !buflen
) break;
6223 max_level
= get_max_level( format
);
6225 switch(ft_face
->glyph
->format
) {
6226 case ft_glyph_format_bitmap
:
6228 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6229 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6231 memset( buf
, 0, needed
);
6233 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6234 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6235 src
+= ft_face
->glyph
->bitmap
.pitch
;
6240 case ft_glyph_format_outline
:
6242 ft_bitmap
.width
= width
;
6243 ft_bitmap
.rows
= height
;
6244 ft_bitmap
.pitch
= pitch
;
6245 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6246 ft_bitmap
.buffer
= buf
;
6249 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6251 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6253 memset(ft_bitmap
.buffer
, 0, buflen
);
6255 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6257 if (max_level
!= 255)
6259 for (row
= 0, start
= buf
; row
< height
; row
++)
6261 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6262 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6270 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6276 case WINE_GGO_HRGB_BITMAP
:
6277 case WINE_GGO_HBGR_BITMAP
:
6278 case WINE_GGO_VRGB_BITMAP
:
6279 case WINE_GGO_VBGR_BITMAP
:
6280 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6282 switch (ft_face
->glyph
->format
)
6284 case FT_GLYPH_FORMAT_BITMAP
:
6289 width
= lpgm
->gmBlackBoxX
;
6290 height
= lpgm
->gmBlackBoxY
;
6292 needed
= pitch
* height
;
6294 if (!buf
|| !buflen
) break;
6296 memset(buf
, 0, buflen
);
6298 src
= ft_face
->glyph
->bitmap
.buffer
;
6299 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6301 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6304 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6306 if ( src
[x
/ 8] & masks
[x
% 8] )
6307 ((unsigned int *)dst
)[x
] = ~0u;
6316 case FT_GLYPH_FORMAT_OUTLINE
:
6320 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6321 INT x_shift
, y_shift
;
6323 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6324 FT_Render_Mode render_mode
=
6325 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6326 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6328 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6330 if ( render_mode
== FT_RENDER_MODE_LCD
)
6332 lpgm
->gmBlackBoxX
+= 2;
6333 lpgm
->gmptGlyphOrigin
.x
-= 1;
6337 lpgm
->gmBlackBoxY
+= 2;
6338 lpgm
->gmptGlyphOrigin
.y
+= 1;
6342 width
= lpgm
->gmBlackBoxX
;
6343 height
= lpgm
->gmBlackBoxY
;
6345 needed
= pitch
* height
;
6347 if (!buf
|| !buflen
) break;
6349 memset(buf
, 0, buflen
);
6351 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6353 if ( needsTransform
)
6354 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6356 if ( pFT_Library_SetLcdFilter
)
6357 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6358 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6360 src
= ft_face
->glyph
->bitmap
.buffer
;
6361 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6362 src_width
= ft_face
->glyph
->bitmap
.width
;
6363 src_height
= ft_face
->glyph
->bitmap
.rows
;
6365 if ( render_mode
== FT_RENDER_MODE_LCD
)
6373 rgb_interval
= src_pitch
;
6378 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6381 src
+= hmul
* -x_shift
;
6382 src_width
-= hmul
* -x_shift
;
6384 else if ( x_shift
> 0 )
6390 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6393 src
+= src_pitch
* vmul
* -y_shift
;
6394 src_height
-= vmul
* -y_shift
;
6396 else if ( y_shift
> 0 )
6398 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
6402 width
= min( width
, src_width
/ hmul
);
6403 height
= min( height
, src_height
/ vmul
);
6407 for ( x
= 0; x
< width
; x
++ )
6411 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6412 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6413 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6414 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6418 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6419 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6420 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6421 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6424 src
+= src_pitch
* vmul
;
6425 dst
+= pitch
/ sizeof(*dst
);
6432 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6444 int contour
, point
= 0, first_pt
;
6445 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6446 TTPOLYGONHEADER
*pph
;
6448 DWORD pph_start
, cpfx
, type
;
6450 if(buflen
== 0) buf
= NULL
;
6452 if (needsTransform
&& buf
) {
6453 pFT_Outline_Transform(outline
, &transMat
);
6456 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6457 /* Ignore contours containing one point */
6458 if(point
== outline
->contours
[contour
]) {
6464 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6467 pph
->dwType
= TT_POLYGON_TYPE
;
6468 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6470 needed
+= sizeof(*pph
);
6472 while(point
<= outline
->contours
[contour
]) {
6473 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6474 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6475 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6479 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6482 } while(point
<= outline
->contours
[contour
] &&
6483 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6484 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6485 /* At the end of a contour Windows adds the start point, but
6487 if(point
> outline
->contours
[contour
] &&
6488 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6490 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6492 } else if(point
<= outline
->contours
[contour
] &&
6493 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6494 /* add closing pt for bezier */
6496 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6504 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6507 pph
->cb
= needed
- pph_start
;
6513 /* Convert the quadratic Beziers to cubic Beziers.
6514 The parametric eqn for a cubic Bezier is, from PLRM:
6515 r(t) = at^3 + bt^2 + ct + r0
6516 with the control points:
6521 A quadratic Bezier has the form:
6522 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6524 So equating powers of t leads to:
6525 r1 = 2/3 p1 + 1/3 p0
6526 r2 = 2/3 p1 + 1/3 p2
6527 and of course r0 = p0, r3 = p2
6530 int contour
, point
= 0, first_pt
;
6531 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6532 TTPOLYGONHEADER
*pph
;
6534 DWORD pph_start
, cpfx
, type
;
6535 FT_Vector cubic_control
[4];
6536 if(buflen
== 0) buf
= NULL
;
6538 if (needsTransform
&& buf
) {
6539 pFT_Outline_Transform(outline
, &transMat
);
6542 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6544 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6547 pph
->dwType
= TT_POLYGON_TYPE
;
6548 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6550 needed
+= sizeof(*pph
);
6552 while(point
<= outline
->contours
[contour
]) {
6553 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6554 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6555 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6558 if(type
== TT_PRIM_LINE
) {
6560 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6564 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6567 /* FIXME: Possible optimization in endpoint calculation
6568 if there are two consecutive curves */
6569 cubic_control
[0] = outline
->points
[point
-1];
6570 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6571 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6572 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6573 cubic_control
[0].x
>>= 1;
6574 cubic_control
[0].y
>>= 1;
6576 if(point
+1 > outline
->contours
[contour
])
6577 cubic_control
[3] = outline
->points
[first_pt
];
6579 cubic_control
[3] = outline
->points
[point
+1];
6580 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6581 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6582 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6583 cubic_control
[3].x
>>= 1;
6584 cubic_control
[3].y
>>= 1;
6587 /* r1 = 1/3 p0 + 2/3 p1
6588 r2 = 1/3 p2 + 2/3 p1 */
6589 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6590 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6591 cubic_control
[2] = cubic_control
[1];
6592 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6593 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6594 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6595 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6597 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6598 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6599 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6604 } while(point
<= outline
->contours
[contour
] &&
6605 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6606 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6607 /* At the end of a contour Windows adds the start point,
6608 but only for Beziers and we've already done that.
6610 if(point
<= outline
->contours
[contour
] &&
6611 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6612 /* This is the closing pt of a bezier, but we've already
6613 added it, so just inc point and carry on */
6620 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6623 pph
->cb
= needed
- pph_start
;
6629 FIXME("Unsupported format %d\n", format
);
6635 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6637 FT_Face ft_face
= font
->ft_face
;
6638 FT_WinFNT_HeaderRec winfnt_header
;
6639 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6640 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6641 font
->potm
->otmSize
= size
;
6643 #define TM font->potm->otmTextMetrics
6644 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6646 TM
.tmHeight
= winfnt_header
.pixel_height
;
6647 TM
.tmAscent
= winfnt_header
.ascent
;
6648 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6649 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6650 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6651 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6652 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6653 TM
.tmWeight
= winfnt_header
.weight
;
6655 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6656 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6657 TM
.tmFirstChar
= winfnt_header
.first_char
;
6658 TM
.tmLastChar
= winfnt_header
.last_char
;
6659 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6660 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6661 TM
.tmItalic
= winfnt_header
.italic
;
6662 TM
.tmUnderlined
= font
->underline
;
6663 TM
.tmStruckOut
= font
->strikeout
;
6664 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6665 TM
.tmCharSet
= winfnt_header
.charset
;
6669 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6670 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6671 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6672 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6673 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6674 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6675 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6676 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6678 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6679 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6681 TM
.tmLastChar
= 255;
6682 TM
.tmDefaultChar
= 32;
6683 TM
.tmBreakChar
= 32;
6684 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6685 TM
.tmUnderlined
= font
->underline
;
6686 TM
.tmStruckOut
= font
->strikeout
;
6687 /* NB inverted meaning of TMPF_FIXED_PITCH */
6688 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6689 TM
.tmCharSet
= font
->charset
;
6697 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6699 double scale_x
, scale_y
;
6703 scale_x
= (double)font
->aveWidth
;
6704 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6707 scale_x
= font
->scale_y
;
6709 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6710 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6712 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6713 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6715 SCALE_Y(ptm
->tmHeight
);
6716 SCALE_Y(ptm
->tmAscent
);
6717 SCALE_Y(ptm
->tmDescent
);
6718 SCALE_Y(ptm
->tmInternalLeading
);
6719 SCALE_Y(ptm
->tmExternalLeading
);
6720 SCALE_Y(ptm
->tmOverhang
);
6722 SCALE_X(ptm
->tmAveCharWidth
);
6723 SCALE_X(ptm
->tmMaxCharWidth
);
6729 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6731 double scale_x
, scale_y
;
6735 scale_x
= (double)font
->aveWidth
;
6736 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6739 scale_x
= font
->scale_y
;
6741 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6742 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6744 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6746 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6747 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6749 SCALE_Y(potm
->otmAscent
);
6750 SCALE_Y(potm
->otmDescent
);
6751 SCALE_Y(potm
->otmLineGap
);
6752 SCALE_Y(potm
->otmsCapEmHeight
);
6753 SCALE_Y(potm
->otmsXHeight
);
6754 SCALE_Y(potm
->otmrcFontBox
.top
);
6755 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6756 SCALE_X(potm
->otmrcFontBox
.left
);
6757 SCALE_X(potm
->otmrcFontBox
.right
);
6758 SCALE_Y(potm
->otmMacAscent
);
6759 SCALE_Y(potm
->otmMacDescent
);
6760 SCALE_Y(potm
->otmMacLineGap
);
6761 SCALE_X(potm
->otmptSubscriptSize
.x
);
6762 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6763 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6764 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6765 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6766 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6767 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6768 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6769 SCALE_Y(potm
->otmsStrikeoutSize
);
6770 SCALE_Y(potm
->otmsStrikeoutPosition
);
6771 SCALE_Y(potm
->otmsUnderscoreSize
);
6772 SCALE_Y(potm
->otmsUnderscorePosition
);
6778 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6782 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6784 /* Make sure that the font has sane width/height ratio */
6787 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6789 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6794 *ptm
= font
->potm
->otmTextMetrics
;
6795 scale_font_metrics(font
, ptm
);
6799 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6803 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6805 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6811 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6814 FT_Face ft_face
= font
->ft_face
;
6815 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
6817 TT_HoriHeader
*pHori
;
6818 TT_Postscript
*pPost
;
6820 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
6822 INT ascent
, descent
;
6824 TRACE("font=%p\n", font
);
6826 if(!FT_IS_SCALABLE(ft_face
))
6829 needed
= sizeof(*font
->potm
);
6831 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6832 family_nameW
= strdupW(font
->name
);
6834 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
6836 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6839 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6840 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
6842 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
6844 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
6846 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6849 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6850 face_nameW
= strdupW(font
->name
);
6852 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
6853 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
6855 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
6857 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6860 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
6861 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6862 full_nameW
= strdupW(fake_nameW
);
6864 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
6866 /* These names should be read from the TT name table */
6868 /* length of otmpFamilyName */
6871 /* length of otmpFaceName */
6874 /* length of otmpStyleName */
6877 /* length of otmpFullName */
6881 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
6883 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6885 FIXME("Can't find OS/2 table - not TT font?\n");
6889 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6891 FIXME("Can't find HHEA table - not TT font?\n");
6895 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6897 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",
6898 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6899 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6900 pOS2
->xAvgCharWidth
,
6901 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6902 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6903 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6905 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6906 font
->potm
->otmSize
= needed
;
6908 #define TM font->potm->otmTextMetrics
6910 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6911 ascent
= pHori
->Ascender
;
6912 descent
= -pHori
->Descender
;
6914 ascent
= pOS2
->usWinAscent
;
6915 descent
= pOS2
->usWinDescent
;
6918 font
->ntmCellHeight
= ascent
+ descent
;
6919 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6921 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6922 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6925 TM
.tmAscent
= font
->yMax
;
6926 TM
.tmDescent
= -font
->yMin
;
6927 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6929 TM
.tmAscent
= SCALE_Y(ascent
);
6930 TM
.tmDescent
= SCALE_Y(descent
);
6931 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
6934 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6937 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6939 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
6940 ((ascent
+ descent
) -
6941 (pHori
->Ascender
- pHori
->Descender
))));
6943 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
6944 if (TM
.tmAveCharWidth
== 0) {
6945 TM
.tmAveCharWidth
= 1;
6947 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
6948 TM
.tmWeight
= FW_REGULAR
;
6949 if (font
->fake_bold
)
6950 TM
.tmWeight
= FW_BOLD
;
6953 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6955 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6956 TM
.tmWeight
= pOS2
->usWeightClass
;
6958 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6959 TM
.tmWeight
= pOS2
->usWeightClass
;
6962 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6963 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6964 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6965 * symbol range to 0 - f0ff
6968 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6973 case 1257: /* Baltic */
6974 TM
.tmLastChar
= 0xf8fd;
6977 TM
.tmLastChar
= 0xf0ff;
6979 TM
.tmBreakChar
= 0x20;
6980 TM
.tmDefaultChar
= 0x1f;
6984 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6985 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6987 if(pOS2
->usFirstCharIndex
<= 1)
6988 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6989 else if (pOS2
->usFirstCharIndex
> 0xff)
6990 TM
.tmBreakChar
= 0x20;
6992 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6993 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6995 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6996 TM
.tmUnderlined
= font
->underline
;
6997 TM
.tmStruckOut
= font
->strikeout
;
6999 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7000 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7001 (pOS2
->version
== 0xFFFFU
||
7002 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7003 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7005 TM
.tmPitchAndFamily
= 0;
7007 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7009 case PAN_FAMILY_SCRIPT
:
7010 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7013 case PAN_FAMILY_DECORATIVE
:
7014 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7019 case PAN_FAMILY_TEXT_DISPLAY
:
7020 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7021 /* which is clearly not what the panose spec says. */
7023 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7024 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7025 TM
.tmPitchAndFamily
= FF_MODERN
;
7028 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7033 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7036 case PAN_SERIF_COVE
:
7037 case PAN_SERIF_OBTUSE_COVE
:
7038 case PAN_SERIF_SQUARE_COVE
:
7039 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7040 case PAN_SERIF_SQUARE
:
7041 case PAN_SERIF_THIN
:
7042 case PAN_SERIF_BONE
:
7043 case PAN_SERIF_EXAGGERATED
:
7044 case PAN_SERIF_TRIANGLE
:
7045 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7048 case PAN_SERIF_NORMAL_SANS
:
7049 case PAN_SERIF_OBTUSE_SANS
:
7050 case PAN_SERIF_PERP_SANS
:
7051 case PAN_SERIF_FLARED
:
7052 case PAN_SERIF_ROUNDED
:
7053 TM
.tmPitchAndFamily
|= FF_SWISS
;
7060 if(FT_IS_SCALABLE(ft_face
))
7061 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7063 if(FT_IS_SFNT(ft_face
))
7065 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7066 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7068 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7071 TM
.tmCharSet
= font
->charset
;
7073 font
->potm
->otmFiller
= 0;
7074 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7075 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7076 font
->potm
->otmfsType
= pOS2
->fsType
;
7077 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7078 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7079 font
->potm
->otmItalicAngle
= 0; /* POST table */
7080 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7081 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7082 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7083 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7084 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7085 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7086 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7087 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7088 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7089 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7090 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7091 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7092 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7093 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7094 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7095 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7096 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7097 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7098 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7099 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7100 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7101 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7102 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7103 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7105 font
->potm
->otmsUnderscoreSize
= 0;
7106 font
->potm
->otmsUnderscorePosition
= 0;
7108 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7109 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7115 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7116 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7117 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7118 strcpyW((WCHAR
*)cp
, family_nameW
);
7120 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7121 strcpyW((WCHAR
*)cp
, style_nameW
);
7123 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7124 strcpyW((WCHAR
*)cp
, face_nameW
);
7126 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7127 strcpyW((WCHAR
*)cp
, full_nameW
);
7131 HeapFree(GetProcessHeap(), 0, style_nameW
);
7132 HeapFree(GetProcessHeap(), 0, family_nameW
);
7133 HeapFree(GetProcessHeap(), 0, face_nameW
);
7134 HeapFree(GetProcessHeap(), 0, full_nameW
);
7138 /*************************************************************
7139 * freetype_GetGlyphOutline
7141 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7142 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7144 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7150 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7151 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7155 EnterCriticalSection( &freetype_cs
);
7156 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7157 LeaveCriticalSection( &freetype_cs
);
7161 /*************************************************************
7162 * freetype_GetTextMetrics
7164 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7166 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7171 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7172 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7176 EnterCriticalSection( &freetype_cs
);
7177 ret
= get_text_metrics( physdev
->font
, metrics
);
7178 LeaveCriticalSection( &freetype_cs
);
7182 /*************************************************************
7183 * freetype_GetOutlineTextMetrics
7185 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7187 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7192 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7193 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7196 TRACE("font=%p\n", physdev
->font
);
7198 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7201 EnterCriticalSection( &freetype_cs
);
7203 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7205 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7207 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7208 scale_outline_font_metrics(physdev
->font
, potm
);
7210 ret
= physdev
->font
->potm
->otmSize
;
7212 LeaveCriticalSection( &freetype_cs
);
7216 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7218 child
->font
= alloc_font();
7219 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7220 if(!child
->font
->ft_face
)
7222 free_font(child
->font
);
7227 child
->font
->font_desc
= font
->font_desc
;
7228 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7229 child
->font
->orientation
= font
->orientation
;
7230 child
->font
->scale_y
= font
->scale_y
;
7231 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7232 child
->font
->base_font
= font
;
7233 TRACE("created child font %p for base %p\n", child
->font
, font
);
7237 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
7240 CHILD_FONT
*child_font
;
7243 font
= font
->base_font
;
7245 *linked_font
= font
;
7247 if((*glyph
= get_glyph_index(font
, c
)))
7249 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7253 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7255 if(!child_font
->font
)
7256 if(!load_child_font(font
, child_font
))
7259 if(!child_font
->font
->ft_face
)
7261 g
= get_glyph_index(child_font
->font
, c
);
7262 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7266 *linked_font
= child_font
->font
;
7273 /*************************************************************
7274 * freetype_GetCharWidth
7276 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7278 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7282 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7286 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7287 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7290 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7293 EnterCriticalSection( &freetype_cs
);
7294 for(c
= firstChar
; c
<= lastChar
; c
++) {
7295 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7296 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7298 LeaveCriticalSection( &freetype_cs
);
7302 /*************************************************************
7303 * freetype_GetCharABCWidths
7305 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7307 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7310 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7314 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7315 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7318 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7321 EnterCriticalSection( &freetype_cs
);
7323 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7324 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7326 LeaveCriticalSection( &freetype_cs
);
7330 /*************************************************************
7331 * freetype_GetCharABCWidthsI
7333 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7335 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7338 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7342 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7343 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7346 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7350 EnterCriticalSection( &freetype_cs
);
7352 for(c
= 0; c
< count
; c
++, buffer
++)
7353 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7354 &gm
, buffer
, 0, NULL
, &identity
);
7356 LeaveCriticalSection( &freetype_cs
);
7360 /*************************************************************
7361 * freetype_GetTextExtentExPoint
7363 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7365 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7369 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7373 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7374 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7377 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7380 EnterCriticalSection( &freetype_cs
);
7382 for (idx
= pos
= 0; idx
< count
; idx
++)
7384 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7385 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7389 LeaveCriticalSection( &freetype_cs
);
7393 /*************************************************************
7394 * freetype_GetTextExtentExPointI
7396 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7398 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7402 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7406 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7407 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7410 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7413 EnterCriticalSection( &freetype_cs
);
7415 for (idx
= pos
= 0; idx
< count
; idx
++)
7417 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7418 &gm
, &abc
, 0, NULL
, &identity
);
7419 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7423 LeaveCriticalSection( &freetype_cs
);
7427 /*************************************************************
7428 * freetype_GetFontData
7430 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7432 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7436 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7437 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7440 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7441 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7442 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7444 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7447 /*************************************************************
7448 * freetype_GetTextFace
7450 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7453 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7457 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7458 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7461 n
= strlenW(physdev
->font
->name
) + 1;
7464 lstrcpynW(str
, physdev
->font
->name
, count
);
7470 /*************************************************************
7471 * freetype_GetTextCharsetInfo
7473 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7475 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7479 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7480 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7482 if (fs
) *fs
= physdev
->font
->fs
;
7483 return physdev
->font
->charset
;
7486 /* Retrieve a list of supported Unicode ranges for a given font.
7487 * Can be called with NULL gs to calculate the buffer size. Returns
7488 * the number of ranges found.
7490 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7492 DWORD num_ranges
= 0;
7494 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7497 FT_ULong char_code
, char_code_prev
;
7500 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7502 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7503 face
->num_glyphs
, glyph_code
, char_code
);
7505 if (!glyph_code
) return 0;
7509 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7510 gs
->ranges
[0].cGlyphs
= 0;
7511 gs
->cGlyphsSupported
= 0;
7517 if (char_code
< char_code_prev
)
7519 ERR("expected increasing char code from FT_Get_Next_Char\n");
7522 if (char_code
- char_code_prev
> 1)
7527 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7528 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7529 gs
->cGlyphsSupported
++;
7534 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7535 gs
->cGlyphsSupported
++;
7537 char_code_prev
= char_code
;
7538 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7542 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7547 /*************************************************************
7548 * freetype_GetFontUnicodeRanges
7550 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7552 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7553 DWORD size
, num_ranges
;
7557 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7558 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7561 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7562 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7565 glyphset
->cbThis
= size
;
7566 glyphset
->cRanges
= num_ranges
;
7567 glyphset
->flAccel
= 0;
7572 /*************************************************************
7573 * freetype_FontIsLinked
7575 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7577 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7582 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7583 return dev
->funcs
->pFontIsLinked( dev
);
7587 EnterCriticalSection( &freetype_cs
);
7588 ret
= !list_empty(&physdev
->font
->child_fonts
);
7589 LeaveCriticalSection( &freetype_cs
);
7593 /*************************************************************************
7594 * GetRasterizerCaps (GDI32.@)
7596 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7598 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7599 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7600 lprs
->nLanguageID
= 0;
7604 /*************************************************************
7605 * freetype_GdiRealizationInfo
7607 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7609 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7610 realization_info_t
*info
= ptr
;
7614 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7615 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7618 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7621 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7624 info
->cache_num
= physdev
->font
->cache_num
;
7625 info
->unknown2
= -1;
7629 /*************************************************************************
7630 * Kerning support for TrueType fonts
7632 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7634 struct TT_kern_table
7640 struct TT_kern_subtable
7649 USHORT horizontal
: 1;
7651 USHORT cross_stream
: 1;
7652 USHORT override
: 1;
7653 USHORT reserved1
: 4;
7659 struct TT_format0_kern_subtable
7663 USHORT entrySelector
;
7674 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7675 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7676 const USHORT
*glyph_to_char
,
7677 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7680 const struct TT_kern_pair
*tt_kern_pair
;
7682 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7684 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7686 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7687 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7688 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7690 if (!kern_pair
|| !cPairs
)
7693 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7695 nPairs
= min(nPairs
, cPairs
);
7697 for (i
= 0; i
< nPairs
; i
++)
7699 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7700 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7701 /* this algorithm appears to better match what Windows does */
7702 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7703 if (kern_pair
->iKernAmount
< 0)
7705 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7706 kern_pair
->iKernAmount
-= font
->ppem
;
7708 else if (kern_pair
->iKernAmount
> 0)
7710 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7711 kern_pair
->iKernAmount
+= font
->ppem
;
7713 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7715 TRACE("left %u right %u value %d\n",
7716 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7720 TRACE("copied %u entries\n", nPairs
);
7724 /*************************************************************
7725 * freetype_GetKerningPairs
7727 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7731 const struct TT_kern_table
*tt_kern_table
;
7732 const struct TT_kern_subtable
*tt_kern_subtable
;
7734 USHORT
*glyph_to_char
;
7736 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7738 if (!(font
= physdev
->font
))
7740 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7741 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7745 EnterCriticalSection( &freetype_cs
);
7746 if (font
->total_kern_pairs
!= (DWORD
)-1)
7748 if (cPairs
&& kern_pair
)
7750 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7751 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7753 else cPairs
= font
->total_kern_pairs
;
7755 LeaveCriticalSection( &freetype_cs
);
7759 font
->total_kern_pairs
= 0;
7761 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7763 if (length
== GDI_ERROR
)
7765 TRACE("no kerning data in the font\n");
7766 LeaveCriticalSection( &freetype_cs
);
7770 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7773 WARN("Out of memory\n");
7774 LeaveCriticalSection( &freetype_cs
);
7778 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7780 /* build a glyph index to char code map */
7781 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7784 WARN("Out of memory allocating a glyph index to char code map\n");
7785 HeapFree(GetProcessHeap(), 0, buf
);
7786 LeaveCriticalSection( &freetype_cs
);
7790 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7796 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7798 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7799 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7803 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7805 /* FIXME: This doesn't match what Windows does: it does some fancy
7806 * things with duplicate glyph index to char code mappings, while
7807 * we just avoid overriding existing entries.
7809 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7810 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7812 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7819 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7820 for (n
= 0; n
<= 65535; n
++)
7821 glyph_to_char
[n
] = (USHORT
)n
;
7824 tt_kern_table
= buf
;
7825 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7826 TRACE("version %u, nTables %u\n",
7827 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7829 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7831 for (i
= 0; i
< nTables
; i
++)
7833 struct TT_kern_subtable tt_kern_subtable_copy
;
7835 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7836 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7837 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7839 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7840 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7841 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7843 /* According to the TrueType specification this is the only format
7844 * that will be properly interpreted by Windows and OS/2
7846 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7848 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7850 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7851 glyph_to_char
, NULL
, 0);
7852 font
->total_kern_pairs
+= new_chunk
;
7854 if (!font
->kern_pairs
)
7855 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7856 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7858 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7859 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7861 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7862 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7865 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7867 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7870 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7871 HeapFree(GetProcessHeap(), 0, buf
);
7873 if (cPairs
&& kern_pair
)
7875 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7876 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7878 else cPairs
= font
->total_kern_pairs
;
7880 LeaveCriticalSection( &freetype_cs
);
7884 static const struct gdi_dc_funcs freetype_funcs
=
7886 NULL
, /* pAbortDoc */
7887 NULL
, /* pAbortPath */
7888 NULL
, /* pAlphaBlend */
7889 NULL
, /* pAngleArc */
7892 NULL
, /* pBeginPath */
7893 NULL
, /* pBlendImage */
7895 NULL
, /* pCloseFigure */
7896 NULL
, /* pCreateCompatibleDC */
7897 freetype_CreateDC
, /* pCreateDC */
7898 freetype_DeleteDC
, /* pDeleteDC */
7899 NULL
, /* pDeleteObject */
7900 NULL
, /* pDeviceCapabilities */
7901 NULL
, /* pEllipse */
7903 NULL
, /* pEndPage */
7904 NULL
, /* pEndPath */
7905 freetype_EnumFonts
, /* pEnumFonts */
7906 NULL
, /* pEnumICMProfiles */
7907 NULL
, /* pExcludeClipRect */
7908 NULL
, /* pExtDeviceMode */
7909 NULL
, /* pExtEscape */
7910 NULL
, /* pExtFloodFill */
7911 NULL
, /* pExtSelectClipRgn */
7912 NULL
, /* pExtTextOut */
7913 NULL
, /* pFillPath */
7914 NULL
, /* pFillRgn */
7915 NULL
, /* pFlattenPath */
7916 freetype_FontIsLinked
, /* pFontIsLinked */
7917 NULL
, /* pFrameRgn */
7918 NULL
, /* pGdiComment */
7919 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7920 NULL
, /* pGetBoundsRect */
7921 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7922 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7923 freetype_GetCharWidth
, /* pGetCharWidth */
7924 NULL
, /* pGetDeviceCaps */
7925 NULL
, /* pGetDeviceGammaRamp */
7926 freetype_GetFontData
, /* pGetFontData */
7927 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7928 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7929 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7930 NULL
, /* pGetICMProfile */
7931 NULL
, /* pGetImage */
7932 freetype_GetKerningPairs
, /* pGetKerningPairs */
7933 NULL
, /* pGetNearestColor */
7934 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7935 NULL
, /* pGetPixel */
7936 NULL
, /* pGetSystemPaletteEntries */
7937 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7938 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7939 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7940 freetype_GetTextFace
, /* pGetTextFace */
7941 freetype_GetTextMetrics
, /* pGetTextMetrics */
7942 NULL
, /* pGradientFill */
7943 NULL
, /* pIntersectClipRect */
7944 NULL
, /* pInvertRgn */
7946 NULL
, /* pModifyWorldTransform */
7948 NULL
, /* pOffsetClipRgn */
7949 NULL
, /* pOffsetViewportOrg */
7950 NULL
, /* pOffsetWindowOrg */
7951 NULL
, /* pPaintRgn */
7954 NULL
, /* pPolyBezier */
7955 NULL
, /* pPolyBezierTo */
7956 NULL
, /* pPolyDraw */
7957 NULL
, /* pPolyPolygon */
7958 NULL
, /* pPolyPolyline */
7959 NULL
, /* pPolygon */
7960 NULL
, /* pPolyline */
7961 NULL
, /* pPolylineTo */
7962 NULL
, /* pPutImage */
7963 NULL
, /* pRealizeDefaultPalette */
7964 NULL
, /* pRealizePalette */
7965 NULL
, /* pRectangle */
7966 NULL
, /* pResetDC */
7967 NULL
, /* pRestoreDC */
7968 NULL
, /* pRoundRect */
7970 NULL
, /* pScaleViewportExt */
7971 NULL
, /* pScaleWindowExt */
7972 NULL
, /* pSelectBitmap */
7973 NULL
, /* pSelectBrush */
7974 NULL
, /* pSelectClipPath */
7975 freetype_SelectFont
, /* pSelectFont */
7976 NULL
, /* pSelectPalette */
7977 NULL
, /* pSelectPen */
7978 NULL
, /* pSetArcDirection */
7979 NULL
, /* pSetBkColor */
7980 NULL
, /* pSetBkMode */
7981 NULL
, /* pSetDCBrushColor */
7982 NULL
, /* pSetDCPenColor */
7983 NULL
, /* pSetDIBColorTable */
7984 NULL
, /* pSetDIBitsToDevice */
7985 NULL
, /* pSetDeviceClipping */
7986 NULL
, /* pSetDeviceGammaRamp */
7987 NULL
, /* pSetLayout */
7988 NULL
, /* pSetMapMode */
7989 NULL
, /* pSetMapperFlags */
7990 NULL
, /* pSetPixel */
7991 NULL
, /* pSetPolyFillMode */
7992 NULL
, /* pSetROP2 */
7993 NULL
, /* pSetRelAbs */
7994 NULL
, /* pSetStretchBltMode */
7995 NULL
, /* pSetTextAlign */
7996 NULL
, /* pSetTextCharacterExtra */
7997 NULL
, /* pSetTextColor */
7998 NULL
, /* pSetTextJustification */
7999 NULL
, /* pSetViewportExt */
8000 NULL
, /* pSetViewportOrg */
8001 NULL
, /* pSetWindowExt */
8002 NULL
, /* pSetWindowOrg */
8003 NULL
, /* pSetWorldTransform */
8004 NULL
, /* pStartDoc */
8005 NULL
, /* pStartPage */
8006 NULL
, /* pStretchBlt */
8007 NULL
, /* pStretchDIBits */
8008 NULL
, /* pStrokeAndFillPath */
8009 NULL
, /* pStrokePath */
8010 NULL
, /* pUnrealizePalette */
8011 NULL
, /* pWidenPath */
8012 NULL
, /* wine_get_wgl_driver */
8013 GDI_PRIORITY_FONT_DRV
/* priority */
8016 #else /* HAVE_FREETYPE */
8018 /*************************************************************************/
8020 BOOL
WineEngInit(void)
8025 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8027 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8031 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8033 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8037 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8039 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8043 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8044 LPCWSTR font_file
, LPCWSTR font_path
)
8050 /*************************************************************************
8051 * GetRasterizerCaps (GDI32.@)
8053 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8055 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8057 lprs
->nLanguageID
= 0;
8061 #endif /* HAVE_FREETYPE */