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 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
5847 LeaveCriticalSection( &freetype_cs
);
5851 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5853 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5854 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5857 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5859 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5860 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5863 static inline BYTE
get_max_level( UINT format
)
5867 case GGO_GRAY2_BITMAP
: return 4;
5868 case GGO_GRAY4_BITMAP
: return 16;
5869 case GGO_GRAY8_BITMAP
: return 64;
5874 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5876 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5877 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
5880 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5881 FT_Face ft_face
= incoming_font
->ft_face
;
5882 GdiFont
*font
= incoming_font
;
5883 FT_Glyph_Metrics metrics
;
5884 FT_UInt glyph_index
;
5885 DWORD width
, height
, pitch
, needed
= 0;
5886 FT_Bitmap ft_bitmap
;
5888 INT left
, right
, top
= 0, bottom
= 0, adv
;
5890 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5891 double widthRatio
= 1.0;
5892 FT_Matrix transMat
= identityMat
;
5893 FT_Matrix transMatUnrotated
;
5894 BOOL needsTransform
= FALSE
;
5895 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5896 UINT original_index
;
5897 LONG avgAdvance
= 0;
5900 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5901 buflen
, buf
, lpmat
);
5903 TRACE("font transform %f %f %f %f\n",
5904 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5905 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5907 if(format
& GGO_GLYPH_INDEX
) {
5908 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5909 original_index
= glyph
;
5910 format
&= ~GGO_GLYPH_INDEX
;
5912 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5913 ft_face
= font
->ft_face
;
5914 original_index
= glyph_index
;
5917 if(format
& GGO_UNHINTED
) {
5918 load_flags
|= FT_LOAD_NO_HINTING
;
5919 format
&= ~GGO_UNHINTED
;
5922 /* tategaki never appears to happen to lower glyph index */
5923 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5926 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5927 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5928 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5929 font
->gmsize
* sizeof(GM
*));
5931 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5932 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5934 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5935 *abc
= FONT_GM(font
,original_index
)->abc
;
5936 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5937 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5938 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5939 return 1; /* FIXME */
5943 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5944 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5946 /* Scaling factor */
5951 get_text_metrics(font
, &tm
);
5953 widthRatio
= (double)font
->aveWidth
;
5954 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5957 widthRatio
= font
->scale_y
;
5959 /* Scaling transform */
5960 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5963 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5966 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5968 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5969 needsTransform
= TRUE
;
5972 /* Slant transform */
5973 if (font
->fake_italic
) {
5976 slantMat
.xx
= (1 << 16);
5977 slantMat
.xy
= ((1 << 16) >> 2);
5979 slantMat
.yy
= (1 << 16);
5980 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5981 needsTransform
= TRUE
;
5984 /* Rotation transform */
5985 transMatUnrotated
= transMat
;
5986 if(font
->orientation
&& !tategaki
) {
5987 FT_Matrix rotationMat
;
5989 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5990 pFT_Vector_Unit(&vecAngle
, angle
);
5991 rotationMat
.xx
= vecAngle
.x
;
5992 rotationMat
.xy
= -vecAngle
.y
;
5993 rotationMat
.yx
= -rotationMat
.xy
;
5994 rotationMat
.yy
= rotationMat
.xx
;
5996 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5997 needsTransform
= TRUE
;
6000 /* World transform */
6001 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6004 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6005 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6006 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6007 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6008 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6009 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6010 needsTransform
= TRUE
;
6013 /* Extra transformation specified by caller */
6014 if (!is_identity_MAT2(lpmat
))
6017 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6018 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6019 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6020 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6021 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6022 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6023 needsTransform
= TRUE
;
6026 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6028 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6031 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6035 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6036 * by the text metrics. The proper behavior is to clip the glyph metrics to
6037 * fit within the maximums specified in the text metrics. */
6038 metrics
= ft_face
->glyph
->metrics
;
6039 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6040 get_bitmap_text_metrics(incoming_font
)) {
6041 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6042 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6043 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6044 metrics
.horiBearingY
= top
;
6045 metrics
.height
= top
- bottom
;
6047 /* TODO: Are we supposed to clip the width as well...? */
6048 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6051 if(FT_IS_SCALABLE(incoming_font
->ft_face
)) {
6053 if (get_text_metrics(incoming_font
, &tm
) &&
6054 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6055 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6056 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6058 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6059 TRACE("Fixed-pitch full-width character detected\n");
6061 avgAdvance
= 0; /* cancel this feature */
6065 if(!needsTransform
) {
6066 left
= (INT
)(metrics
.horiBearingX
) & -64;
6067 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6069 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6071 adv
= (INT
)avgAdvance
* 2;
6073 top
= (metrics
.horiBearingY
+ 63) & -64;
6074 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6075 lpgm
->gmCellIncX
= adv
;
6076 lpgm
->gmCellIncY
= 0;
6083 for(xc
= 0; xc
< 2; xc
++) {
6084 for(yc
= 0; yc
< 2; yc
++) {
6085 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6086 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6087 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6088 pFT_Vector_Transform(&vec
, &transMat
);
6089 if(xc
== 0 && yc
== 0) {
6090 left
= right
= vec
.x
;
6091 top
= bottom
= vec
.y
;
6093 if(vec
.x
< left
) left
= vec
.x
;
6094 else if(vec
.x
> right
) right
= vec
.x
;
6095 if(vec
.y
< bottom
) bottom
= vec
.y
;
6096 else if(vec
.y
> top
) top
= vec
.y
;
6101 right
= (right
+ 63) & -64;
6102 bottom
= bottom
& -64;
6103 top
= (top
+ 63) & -64;
6105 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6106 vec
.x
= metrics
.horiAdvance
;
6108 pFT_Vector_Transform(&vec
, &transMat
);
6109 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6110 if (!avgAdvance
|| vec
.y
)
6111 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6113 vec
.x
= incoming_font
->ntmAvgWidth
;
6115 pFT_Vector_Transform(&vec
, &transMat
);
6116 lpgm
->gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6119 vec
.x
= metrics
.horiAdvance
;
6121 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6122 if (!avgAdvance
|| vec
.y
)
6123 adv
= (vec
.x
+63) >> 6;
6125 vec
.x
= incoming_font
->ntmAvgWidth
;
6127 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6128 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6132 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6133 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6134 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
6135 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
6136 abc
->abcA
= left
>> 6;
6137 abc
->abcB
= (right
- left
) >> 6;
6138 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6140 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6141 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6142 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6144 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6145 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6147 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6148 FONT_GM(font
,original_index
)->abc
= *abc
;
6149 FONT_GM(font
,original_index
)->init
= TRUE
;
6152 if(format
== GGO_METRICS
)
6154 return 1; /* FIXME */
6157 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6158 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6160 TRACE("loaded a bitmap\n");
6166 width
= lpgm
->gmBlackBoxX
;
6167 height
= lpgm
->gmBlackBoxY
;
6168 pitch
= ((width
+ 31) >> 5) << 2;
6169 needed
= pitch
* height
;
6171 if(!buf
|| !buflen
) break;
6173 switch(ft_face
->glyph
->format
) {
6174 case ft_glyph_format_bitmap
:
6176 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6177 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6178 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6180 memcpy(dst
, src
, w
);
6181 src
+= ft_face
->glyph
->bitmap
.pitch
;
6187 case ft_glyph_format_outline
:
6188 ft_bitmap
.width
= width
;
6189 ft_bitmap
.rows
= height
;
6190 ft_bitmap
.pitch
= pitch
;
6191 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6192 ft_bitmap
.buffer
= buf
;
6195 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6197 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6199 /* Note: FreeType will only set 'black' bits for us. */
6200 memset(buf
, 0, needed
);
6201 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6205 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6210 case GGO_GRAY2_BITMAP
:
6211 case GGO_GRAY4_BITMAP
:
6212 case GGO_GRAY8_BITMAP
:
6213 case WINE_GGO_GRAY16_BITMAP
:
6215 unsigned int max_level
, row
, col
;
6218 width
= lpgm
->gmBlackBoxX
;
6219 height
= lpgm
->gmBlackBoxY
;
6220 pitch
= (width
+ 3) / 4 * 4;
6221 needed
= pitch
* height
;
6223 if(!buf
|| !buflen
) break;
6225 max_level
= get_max_level( format
);
6227 switch(ft_face
->glyph
->format
) {
6228 case ft_glyph_format_bitmap
:
6230 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6231 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6233 memset( buf
, 0, needed
);
6235 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6236 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6237 src
+= ft_face
->glyph
->bitmap
.pitch
;
6242 case ft_glyph_format_outline
:
6244 ft_bitmap
.width
= width
;
6245 ft_bitmap
.rows
= height
;
6246 ft_bitmap
.pitch
= pitch
;
6247 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6248 ft_bitmap
.buffer
= buf
;
6251 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6253 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6255 memset(ft_bitmap
.buffer
, 0, buflen
);
6257 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6259 if (max_level
!= 255)
6261 for (row
= 0, start
= buf
; row
< height
; row
++)
6263 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6264 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6272 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6278 case WINE_GGO_HRGB_BITMAP
:
6279 case WINE_GGO_HBGR_BITMAP
:
6280 case WINE_GGO_VRGB_BITMAP
:
6281 case WINE_GGO_VBGR_BITMAP
:
6282 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6284 switch (ft_face
->glyph
->format
)
6286 case FT_GLYPH_FORMAT_BITMAP
:
6291 width
= lpgm
->gmBlackBoxX
;
6292 height
= lpgm
->gmBlackBoxY
;
6294 needed
= pitch
* height
;
6296 if (!buf
|| !buflen
) break;
6298 memset(buf
, 0, buflen
);
6300 src
= ft_face
->glyph
->bitmap
.buffer
;
6301 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6303 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6306 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6308 if ( src
[x
/ 8] & masks
[x
% 8] )
6309 ((unsigned int *)dst
)[x
] = ~0u;
6318 case FT_GLYPH_FORMAT_OUTLINE
:
6322 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6323 INT x_shift
, y_shift
;
6325 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6326 FT_Render_Mode render_mode
=
6327 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6328 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6330 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6332 if ( render_mode
== FT_RENDER_MODE_LCD
)
6334 lpgm
->gmBlackBoxX
+= 2;
6335 lpgm
->gmptGlyphOrigin
.x
-= 1;
6339 lpgm
->gmBlackBoxY
+= 2;
6340 lpgm
->gmptGlyphOrigin
.y
+= 1;
6344 width
= lpgm
->gmBlackBoxX
;
6345 height
= lpgm
->gmBlackBoxY
;
6347 needed
= pitch
* height
;
6349 if (!buf
|| !buflen
) break;
6351 memset(buf
, 0, buflen
);
6353 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6355 if ( needsTransform
)
6356 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6358 if ( pFT_Library_SetLcdFilter
)
6359 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6360 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6362 src
= ft_face
->glyph
->bitmap
.buffer
;
6363 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6364 src_width
= ft_face
->glyph
->bitmap
.width
;
6365 src_height
= ft_face
->glyph
->bitmap
.rows
;
6367 if ( render_mode
== FT_RENDER_MODE_LCD
)
6375 rgb_interval
= src_pitch
;
6380 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6383 src
+= hmul
* -x_shift
;
6384 src_width
-= hmul
* -x_shift
;
6386 else if ( x_shift
> 0 )
6392 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6395 src
+= src_pitch
* vmul
* -y_shift
;
6396 src_height
-= vmul
* -y_shift
;
6398 else if ( y_shift
> 0 )
6400 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
6404 width
= min( width
, src_width
/ hmul
);
6405 height
= min( height
, src_height
/ vmul
);
6409 for ( x
= 0; x
< width
; x
++ )
6413 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6414 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6415 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6416 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6420 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6421 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6422 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6423 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6426 src
+= src_pitch
* vmul
;
6427 dst
+= pitch
/ sizeof(*dst
);
6434 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6446 int contour
, point
= 0, first_pt
;
6447 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6448 TTPOLYGONHEADER
*pph
;
6450 DWORD pph_start
, cpfx
, type
;
6452 if(buflen
== 0) buf
= NULL
;
6454 if (needsTransform
&& buf
) {
6455 pFT_Outline_Transform(outline
, &transMat
);
6458 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6459 /* Ignore contours containing one point */
6460 if(point
== outline
->contours
[contour
]) {
6466 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6469 pph
->dwType
= TT_POLYGON_TYPE
;
6470 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6472 needed
+= sizeof(*pph
);
6474 while(point
<= outline
->contours
[contour
]) {
6475 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6476 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6477 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6481 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6484 } while(point
<= outline
->contours
[contour
] &&
6485 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6486 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6487 /* At the end of a contour Windows adds the start point, but
6489 if(point
> outline
->contours
[contour
] &&
6490 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6492 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6494 } else if(point
<= outline
->contours
[contour
] &&
6495 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6496 /* add closing pt for bezier */
6498 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6506 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6509 pph
->cb
= needed
- pph_start
;
6515 /* Convert the quadratic Beziers to cubic Beziers.
6516 The parametric eqn for a cubic Bezier is, from PLRM:
6517 r(t) = at^3 + bt^2 + ct + r0
6518 with the control points:
6523 A quadratic Bezier has the form:
6524 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6526 So equating powers of t leads to:
6527 r1 = 2/3 p1 + 1/3 p0
6528 r2 = 2/3 p1 + 1/3 p2
6529 and of course r0 = p0, r3 = p2
6532 int contour
, point
= 0, first_pt
;
6533 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6534 TTPOLYGONHEADER
*pph
;
6536 DWORD pph_start
, cpfx
, type
;
6537 FT_Vector cubic_control
[4];
6538 if(buflen
== 0) buf
= NULL
;
6540 if (needsTransform
&& buf
) {
6541 pFT_Outline_Transform(outline
, &transMat
);
6544 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6546 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6549 pph
->dwType
= TT_POLYGON_TYPE
;
6550 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6552 needed
+= sizeof(*pph
);
6554 while(point
<= outline
->contours
[contour
]) {
6555 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6556 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6557 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6560 if(type
== TT_PRIM_LINE
) {
6562 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6566 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6569 /* FIXME: Possible optimization in endpoint calculation
6570 if there are two consecutive curves */
6571 cubic_control
[0] = outline
->points
[point
-1];
6572 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6573 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6574 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6575 cubic_control
[0].x
>>= 1;
6576 cubic_control
[0].y
>>= 1;
6578 if(point
+1 > outline
->contours
[contour
])
6579 cubic_control
[3] = outline
->points
[first_pt
];
6581 cubic_control
[3] = outline
->points
[point
+1];
6582 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6583 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6584 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6585 cubic_control
[3].x
>>= 1;
6586 cubic_control
[3].y
>>= 1;
6589 /* r1 = 1/3 p0 + 2/3 p1
6590 r2 = 1/3 p2 + 2/3 p1 */
6591 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6592 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6593 cubic_control
[2] = cubic_control
[1];
6594 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6595 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6596 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6597 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6599 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6600 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6601 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6606 } while(point
<= outline
->contours
[contour
] &&
6607 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6608 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6609 /* At the end of a contour Windows adds the start point,
6610 but only for Beziers and we've already done that.
6612 if(point
<= outline
->contours
[contour
] &&
6613 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6614 /* This is the closing pt of a bezier, but we've already
6615 added it, so just inc point and carry on */
6622 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6625 pph
->cb
= needed
- pph_start
;
6631 FIXME("Unsupported format %d\n", format
);
6637 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6639 FT_Face ft_face
= font
->ft_face
;
6640 FT_WinFNT_HeaderRec winfnt_header
;
6641 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6642 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6643 font
->potm
->otmSize
= size
;
6645 #define TM font->potm->otmTextMetrics
6646 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6648 TM
.tmHeight
= winfnt_header
.pixel_height
;
6649 TM
.tmAscent
= winfnt_header
.ascent
;
6650 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6651 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6652 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6653 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6654 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6655 TM
.tmWeight
= winfnt_header
.weight
;
6657 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6658 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6659 TM
.tmFirstChar
= winfnt_header
.first_char
;
6660 TM
.tmLastChar
= winfnt_header
.last_char
;
6661 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6662 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6663 TM
.tmItalic
= winfnt_header
.italic
;
6664 TM
.tmUnderlined
= font
->underline
;
6665 TM
.tmStruckOut
= font
->strikeout
;
6666 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6667 TM
.tmCharSet
= winfnt_header
.charset
;
6671 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6672 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6673 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6674 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6675 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6676 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6677 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6678 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6680 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6681 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6683 TM
.tmLastChar
= 255;
6684 TM
.tmDefaultChar
= 32;
6685 TM
.tmBreakChar
= 32;
6686 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6687 TM
.tmUnderlined
= font
->underline
;
6688 TM
.tmStruckOut
= font
->strikeout
;
6689 /* NB inverted meaning of TMPF_FIXED_PITCH */
6690 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6691 TM
.tmCharSet
= font
->charset
;
6699 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6701 double scale_x
, scale_y
;
6705 scale_x
= (double)font
->aveWidth
;
6706 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6709 scale_x
= font
->scale_y
;
6711 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6712 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6714 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6715 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6717 SCALE_Y(ptm
->tmHeight
);
6718 SCALE_Y(ptm
->tmAscent
);
6719 SCALE_Y(ptm
->tmDescent
);
6720 SCALE_Y(ptm
->tmInternalLeading
);
6721 SCALE_Y(ptm
->tmExternalLeading
);
6722 SCALE_Y(ptm
->tmOverhang
);
6724 SCALE_X(ptm
->tmAveCharWidth
);
6725 SCALE_X(ptm
->tmMaxCharWidth
);
6731 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6733 double scale_x
, scale_y
;
6737 scale_x
= (double)font
->aveWidth
;
6738 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6741 scale_x
= font
->scale_y
;
6743 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6744 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6746 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6748 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6749 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6751 SCALE_Y(potm
->otmAscent
);
6752 SCALE_Y(potm
->otmDescent
);
6753 SCALE_Y(potm
->otmLineGap
);
6754 SCALE_Y(potm
->otmsCapEmHeight
);
6755 SCALE_Y(potm
->otmsXHeight
);
6756 SCALE_Y(potm
->otmrcFontBox
.top
);
6757 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6758 SCALE_X(potm
->otmrcFontBox
.left
);
6759 SCALE_X(potm
->otmrcFontBox
.right
);
6760 SCALE_Y(potm
->otmMacAscent
);
6761 SCALE_Y(potm
->otmMacDescent
);
6762 SCALE_Y(potm
->otmMacLineGap
);
6763 SCALE_X(potm
->otmptSubscriptSize
.x
);
6764 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6765 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6766 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6767 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6768 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6769 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6770 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6771 SCALE_Y(potm
->otmsStrikeoutSize
);
6772 SCALE_Y(potm
->otmsStrikeoutPosition
);
6773 SCALE_Y(potm
->otmsUnderscoreSize
);
6774 SCALE_Y(potm
->otmsUnderscorePosition
);
6780 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6784 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6786 /* Make sure that the font has sane width/height ratio */
6789 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6791 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6796 *ptm
= font
->potm
->otmTextMetrics
;
6797 scale_font_metrics(font
, ptm
);
6801 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6805 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6807 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6813 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6816 FT_Face ft_face
= font
->ft_face
;
6817 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
6819 TT_HoriHeader
*pHori
;
6820 TT_Postscript
*pPost
;
6822 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
6824 INT ascent
, descent
;
6826 TRACE("font=%p\n", font
);
6828 if(!FT_IS_SCALABLE(ft_face
))
6831 needed
= sizeof(*font
->potm
);
6833 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6834 family_nameW
= strdupW(font
->name
);
6836 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
6838 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6841 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6842 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
6844 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
6846 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
6848 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6851 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6852 face_nameW
= strdupW(font
->name
);
6854 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
6855 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
6857 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
6859 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6862 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
6863 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6864 full_nameW
= strdupW(fake_nameW
);
6866 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
6868 /* These names should be read from the TT name table */
6870 /* length of otmpFamilyName */
6873 /* length of otmpFaceName */
6876 /* length of otmpStyleName */
6879 /* length of otmpFullName */
6883 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
6885 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6887 FIXME("Can't find OS/2 table - not TT font?\n");
6891 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6893 FIXME("Can't find HHEA table - not TT font?\n");
6897 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6899 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",
6900 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6901 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6902 pOS2
->xAvgCharWidth
,
6903 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6904 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6905 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6907 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6908 font
->potm
->otmSize
= needed
;
6910 #define TM font->potm->otmTextMetrics
6912 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6913 ascent
= pHori
->Ascender
;
6914 descent
= -pHori
->Descender
;
6916 ascent
= pOS2
->usWinAscent
;
6917 descent
= pOS2
->usWinDescent
;
6920 font
->ntmCellHeight
= ascent
+ descent
;
6921 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6923 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6924 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6927 TM
.tmAscent
= font
->yMax
;
6928 TM
.tmDescent
= -font
->yMin
;
6929 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6931 TM
.tmAscent
= SCALE_Y(ascent
);
6932 TM
.tmDescent
= SCALE_Y(descent
);
6933 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
6936 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6939 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6941 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
6942 ((ascent
+ descent
) -
6943 (pHori
->Ascender
- pHori
->Descender
))));
6945 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
6946 if (TM
.tmAveCharWidth
== 0) {
6947 TM
.tmAveCharWidth
= 1;
6949 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
6950 TM
.tmWeight
= FW_REGULAR
;
6951 if (font
->fake_bold
)
6952 TM
.tmWeight
= FW_BOLD
;
6955 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6957 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6958 TM
.tmWeight
= pOS2
->usWeightClass
;
6960 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6961 TM
.tmWeight
= pOS2
->usWeightClass
;
6964 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6965 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6966 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6967 * symbol range to 0 - f0ff
6970 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6975 case 1257: /* Baltic */
6976 TM
.tmLastChar
= 0xf8fd;
6979 TM
.tmLastChar
= 0xf0ff;
6981 TM
.tmBreakChar
= 0x20;
6982 TM
.tmDefaultChar
= 0x1f;
6986 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6987 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6989 if(pOS2
->usFirstCharIndex
<= 1)
6990 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6991 else if (pOS2
->usFirstCharIndex
> 0xff)
6992 TM
.tmBreakChar
= 0x20;
6994 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6995 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6997 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6998 TM
.tmUnderlined
= font
->underline
;
6999 TM
.tmStruckOut
= font
->strikeout
;
7001 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7002 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7003 (pOS2
->version
== 0xFFFFU
||
7004 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7005 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7007 TM
.tmPitchAndFamily
= 0;
7009 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7011 case PAN_FAMILY_SCRIPT
:
7012 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7015 case PAN_FAMILY_DECORATIVE
:
7016 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7021 case PAN_FAMILY_TEXT_DISPLAY
:
7022 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7023 /* which is clearly not what the panose spec says. */
7025 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7026 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7027 TM
.tmPitchAndFamily
= FF_MODERN
;
7030 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7035 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7038 case PAN_SERIF_COVE
:
7039 case PAN_SERIF_OBTUSE_COVE
:
7040 case PAN_SERIF_SQUARE_COVE
:
7041 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7042 case PAN_SERIF_SQUARE
:
7043 case PAN_SERIF_THIN
:
7044 case PAN_SERIF_BONE
:
7045 case PAN_SERIF_EXAGGERATED
:
7046 case PAN_SERIF_TRIANGLE
:
7047 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7050 case PAN_SERIF_NORMAL_SANS
:
7051 case PAN_SERIF_OBTUSE_SANS
:
7052 case PAN_SERIF_PERP_SANS
:
7053 case PAN_SERIF_FLARED
:
7054 case PAN_SERIF_ROUNDED
:
7055 TM
.tmPitchAndFamily
|= FF_SWISS
;
7062 if(FT_IS_SCALABLE(ft_face
))
7063 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7065 if(FT_IS_SFNT(ft_face
))
7067 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7068 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7070 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7073 TM
.tmCharSet
= font
->charset
;
7075 font
->potm
->otmFiller
= 0;
7076 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7077 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7078 font
->potm
->otmfsType
= pOS2
->fsType
;
7079 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7080 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7081 font
->potm
->otmItalicAngle
= 0; /* POST table */
7082 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7083 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7084 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7085 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7086 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7087 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7088 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7089 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7090 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7091 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7092 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7093 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7094 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7095 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7096 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7097 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7098 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7099 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7100 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7101 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7102 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7103 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7104 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7105 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7107 font
->potm
->otmsUnderscoreSize
= 0;
7108 font
->potm
->otmsUnderscorePosition
= 0;
7110 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7111 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7117 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7118 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7119 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7120 strcpyW((WCHAR
*)cp
, family_nameW
);
7122 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7123 strcpyW((WCHAR
*)cp
, style_nameW
);
7125 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7126 strcpyW((WCHAR
*)cp
, face_nameW
);
7128 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7129 strcpyW((WCHAR
*)cp
, full_nameW
);
7133 HeapFree(GetProcessHeap(), 0, style_nameW
);
7134 HeapFree(GetProcessHeap(), 0, family_nameW
);
7135 HeapFree(GetProcessHeap(), 0, face_nameW
);
7136 HeapFree(GetProcessHeap(), 0, full_nameW
);
7140 /*************************************************************
7141 * freetype_GetGlyphOutline
7143 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7144 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7146 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7152 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7153 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7157 EnterCriticalSection( &freetype_cs
);
7158 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7159 LeaveCriticalSection( &freetype_cs
);
7163 /*************************************************************
7164 * freetype_GetTextMetrics
7166 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7168 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7173 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7174 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7178 EnterCriticalSection( &freetype_cs
);
7179 ret
= get_text_metrics( physdev
->font
, metrics
);
7180 LeaveCriticalSection( &freetype_cs
);
7184 /*************************************************************
7185 * freetype_GetOutlineTextMetrics
7187 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7189 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7194 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7195 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7198 TRACE("font=%p\n", physdev
->font
);
7200 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7203 EnterCriticalSection( &freetype_cs
);
7205 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7207 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7209 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7210 scale_outline_font_metrics(physdev
->font
, potm
);
7212 ret
= physdev
->font
->potm
->otmSize
;
7214 LeaveCriticalSection( &freetype_cs
);
7218 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7220 child
->font
= alloc_font();
7221 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7222 if(!child
->font
->ft_face
)
7224 free_font(child
->font
);
7229 child
->font
->font_desc
= font
->font_desc
;
7230 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7231 child
->font
->orientation
= font
->orientation
;
7232 child
->font
->scale_y
= font
->scale_y
;
7233 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7234 child
->font
->base_font
= font
;
7235 TRACE("created child font %p for base %p\n", child
->font
, font
);
7239 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
7242 CHILD_FONT
*child_font
;
7245 font
= font
->base_font
;
7247 *linked_font
= font
;
7249 if((*glyph
= get_glyph_index(font
, c
)))
7251 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7255 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7257 if(!child_font
->font
)
7258 if(!load_child_font(font
, child_font
))
7261 if(!child_font
->font
->ft_face
)
7263 g
= get_glyph_index(child_font
->font
, c
);
7264 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7268 *linked_font
= child_font
->font
;
7275 /*************************************************************
7276 * freetype_GetCharWidth
7278 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7280 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7284 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7288 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7289 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7292 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7295 EnterCriticalSection( &freetype_cs
);
7296 for(c
= firstChar
; c
<= lastChar
; c
++) {
7297 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7298 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7300 LeaveCriticalSection( &freetype_cs
);
7304 /*************************************************************
7305 * freetype_GetCharABCWidths
7307 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7309 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7312 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7316 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7317 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7320 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7323 EnterCriticalSection( &freetype_cs
);
7325 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7326 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7328 LeaveCriticalSection( &freetype_cs
);
7332 /*************************************************************
7333 * freetype_GetCharABCWidthsI
7335 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7337 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7340 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7344 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7345 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7348 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7352 EnterCriticalSection( &freetype_cs
);
7354 for(c
= 0; c
< count
; c
++, buffer
++)
7355 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7356 &gm
, buffer
, 0, NULL
, &identity
);
7358 LeaveCriticalSection( &freetype_cs
);
7362 /*************************************************************
7363 * freetype_GetTextExtentExPoint
7365 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7367 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7371 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7375 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7376 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7379 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7382 EnterCriticalSection( &freetype_cs
);
7384 for (idx
= pos
= 0; idx
< count
; idx
++)
7386 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7387 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7391 LeaveCriticalSection( &freetype_cs
);
7395 /*************************************************************
7396 * freetype_GetTextExtentExPointI
7398 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7400 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7404 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7408 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7409 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7412 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7415 EnterCriticalSection( &freetype_cs
);
7417 for (idx
= pos
= 0; idx
< count
; idx
++)
7419 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7420 &gm
, &abc
, 0, NULL
, &identity
);
7421 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7425 LeaveCriticalSection( &freetype_cs
);
7429 /*************************************************************
7430 * freetype_GetFontData
7432 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7434 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7438 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7439 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7442 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7443 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7444 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7446 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7449 /*************************************************************
7450 * freetype_GetTextFace
7452 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7455 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7459 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7460 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7463 n
= strlenW(physdev
->font
->name
) + 1;
7466 lstrcpynW(str
, physdev
->font
->name
, count
);
7472 /*************************************************************
7473 * freetype_GetTextCharsetInfo
7475 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7477 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7481 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7482 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7484 if (fs
) *fs
= physdev
->font
->fs
;
7485 return physdev
->font
->charset
;
7488 /* Retrieve a list of supported Unicode ranges for a given font.
7489 * Can be called with NULL gs to calculate the buffer size. Returns
7490 * the number of ranges found.
7492 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7494 DWORD num_ranges
= 0;
7496 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7499 FT_ULong char_code
, char_code_prev
;
7502 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7504 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7505 face
->num_glyphs
, glyph_code
, char_code
);
7507 if (!glyph_code
) return 0;
7511 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7512 gs
->ranges
[0].cGlyphs
= 0;
7513 gs
->cGlyphsSupported
= 0;
7519 if (char_code
< char_code_prev
)
7521 ERR("expected increasing char code from FT_Get_Next_Char\n");
7524 if (char_code
- char_code_prev
> 1)
7529 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7530 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7531 gs
->cGlyphsSupported
++;
7536 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7537 gs
->cGlyphsSupported
++;
7539 char_code_prev
= char_code
;
7540 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7544 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7549 /*************************************************************
7550 * freetype_GetFontUnicodeRanges
7552 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7554 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7555 DWORD size
, num_ranges
;
7559 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7560 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7563 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7564 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7567 glyphset
->cbThis
= size
;
7568 glyphset
->cRanges
= num_ranges
;
7569 glyphset
->flAccel
= 0;
7574 /*************************************************************
7575 * freetype_FontIsLinked
7577 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7579 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7584 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7585 return dev
->funcs
->pFontIsLinked( dev
);
7589 EnterCriticalSection( &freetype_cs
);
7590 ret
= !list_empty(&physdev
->font
->child_fonts
);
7591 LeaveCriticalSection( &freetype_cs
);
7595 /*************************************************************************
7596 * GetRasterizerCaps (GDI32.@)
7598 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7600 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7601 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7602 lprs
->nLanguageID
= 0;
7606 /*************************************************************
7607 * freetype_GdiRealizationInfo
7609 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7611 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7612 realization_info_t
*info
= ptr
;
7616 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7617 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7620 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7623 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7626 info
->cache_num
= physdev
->font
->cache_num
;
7627 info
->unknown2
= -1;
7631 /*************************************************************************
7632 * Kerning support for TrueType fonts
7634 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7636 struct TT_kern_table
7642 struct TT_kern_subtable
7651 USHORT horizontal
: 1;
7653 USHORT cross_stream
: 1;
7654 USHORT override
: 1;
7655 USHORT reserved1
: 4;
7661 struct TT_format0_kern_subtable
7665 USHORT entrySelector
;
7676 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7677 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7678 const USHORT
*glyph_to_char
,
7679 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7682 const struct TT_kern_pair
*tt_kern_pair
;
7684 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7686 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7688 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7689 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7690 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7692 if (!kern_pair
|| !cPairs
)
7695 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7697 nPairs
= min(nPairs
, cPairs
);
7699 for (i
= 0; i
< nPairs
; i
++)
7701 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7702 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7703 /* this algorithm appears to better match what Windows does */
7704 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7705 if (kern_pair
->iKernAmount
< 0)
7707 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7708 kern_pair
->iKernAmount
-= font
->ppem
;
7710 else if (kern_pair
->iKernAmount
> 0)
7712 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7713 kern_pair
->iKernAmount
+= font
->ppem
;
7715 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7717 TRACE("left %u right %u value %d\n",
7718 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7722 TRACE("copied %u entries\n", nPairs
);
7726 /*************************************************************
7727 * freetype_GetKerningPairs
7729 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7733 const struct TT_kern_table
*tt_kern_table
;
7734 const struct TT_kern_subtable
*tt_kern_subtable
;
7736 USHORT
*glyph_to_char
;
7738 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7740 if (!(font
= physdev
->font
))
7742 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7743 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7747 EnterCriticalSection( &freetype_cs
);
7748 if (font
->total_kern_pairs
!= (DWORD
)-1)
7750 if (cPairs
&& kern_pair
)
7752 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7753 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7755 else cPairs
= font
->total_kern_pairs
;
7757 LeaveCriticalSection( &freetype_cs
);
7761 font
->total_kern_pairs
= 0;
7763 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7765 if (length
== GDI_ERROR
)
7767 TRACE("no kerning data in the font\n");
7768 LeaveCriticalSection( &freetype_cs
);
7772 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7775 WARN("Out of memory\n");
7776 LeaveCriticalSection( &freetype_cs
);
7780 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7782 /* build a glyph index to char code map */
7783 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7786 WARN("Out of memory allocating a glyph index to char code map\n");
7787 HeapFree(GetProcessHeap(), 0, buf
);
7788 LeaveCriticalSection( &freetype_cs
);
7792 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7798 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7800 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7801 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7805 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7807 /* FIXME: This doesn't match what Windows does: it does some fancy
7808 * things with duplicate glyph index to char code mappings, while
7809 * we just avoid overriding existing entries.
7811 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7812 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7814 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7821 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7822 for (n
= 0; n
<= 65535; n
++)
7823 glyph_to_char
[n
] = (USHORT
)n
;
7826 tt_kern_table
= buf
;
7827 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7828 TRACE("version %u, nTables %u\n",
7829 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7831 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7833 for (i
= 0; i
< nTables
; i
++)
7835 struct TT_kern_subtable tt_kern_subtable_copy
;
7837 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7838 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7839 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7841 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7842 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7843 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7845 /* According to the TrueType specification this is the only format
7846 * that will be properly interpreted by Windows and OS/2
7848 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7850 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7852 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7853 glyph_to_char
, NULL
, 0);
7854 font
->total_kern_pairs
+= new_chunk
;
7856 if (!font
->kern_pairs
)
7857 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7858 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7860 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7861 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7863 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7864 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7867 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7869 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7872 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7873 HeapFree(GetProcessHeap(), 0, buf
);
7875 if (cPairs
&& kern_pair
)
7877 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7878 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7880 else cPairs
= font
->total_kern_pairs
;
7882 LeaveCriticalSection( &freetype_cs
);
7886 static const struct gdi_dc_funcs freetype_funcs
=
7888 NULL
, /* pAbortDoc */
7889 NULL
, /* pAbortPath */
7890 NULL
, /* pAlphaBlend */
7891 NULL
, /* pAngleArc */
7894 NULL
, /* pBeginPath */
7895 NULL
, /* pBlendImage */
7897 NULL
, /* pCloseFigure */
7898 NULL
, /* pCreateCompatibleDC */
7899 freetype_CreateDC
, /* pCreateDC */
7900 freetype_DeleteDC
, /* pDeleteDC */
7901 NULL
, /* pDeleteObject */
7902 NULL
, /* pDeviceCapabilities */
7903 NULL
, /* pEllipse */
7905 NULL
, /* pEndPage */
7906 NULL
, /* pEndPath */
7907 freetype_EnumFonts
, /* pEnumFonts */
7908 NULL
, /* pEnumICMProfiles */
7909 NULL
, /* pExcludeClipRect */
7910 NULL
, /* pExtDeviceMode */
7911 NULL
, /* pExtEscape */
7912 NULL
, /* pExtFloodFill */
7913 NULL
, /* pExtSelectClipRgn */
7914 NULL
, /* pExtTextOut */
7915 NULL
, /* pFillPath */
7916 NULL
, /* pFillRgn */
7917 NULL
, /* pFlattenPath */
7918 freetype_FontIsLinked
, /* pFontIsLinked */
7919 NULL
, /* pFrameRgn */
7920 NULL
, /* pGdiComment */
7921 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7922 NULL
, /* pGetBoundsRect */
7923 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7924 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7925 freetype_GetCharWidth
, /* pGetCharWidth */
7926 NULL
, /* pGetDeviceCaps */
7927 NULL
, /* pGetDeviceGammaRamp */
7928 freetype_GetFontData
, /* pGetFontData */
7929 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7930 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7931 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7932 NULL
, /* pGetICMProfile */
7933 NULL
, /* pGetImage */
7934 freetype_GetKerningPairs
, /* pGetKerningPairs */
7935 NULL
, /* pGetNearestColor */
7936 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7937 NULL
, /* pGetPixel */
7938 NULL
, /* pGetSystemPaletteEntries */
7939 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7940 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7941 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7942 freetype_GetTextFace
, /* pGetTextFace */
7943 freetype_GetTextMetrics
, /* pGetTextMetrics */
7944 NULL
, /* pGradientFill */
7945 NULL
, /* pIntersectClipRect */
7946 NULL
, /* pInvertRgn */
7948 NULL
, /* pModifyWorldTransform */
7950 NULL
, /* pOffsetClipRgn */
7951 NULL
, /* pOffsetViewportOrg */
7952 NULL
, /* pOffsetWindowOrg */
7953 NULL
, /* pPaintRgn */
7956 NULL
, /* pPolyBezier */
7957 NULL
, /* pPolyBezierTo */
7958 NULL
, /* pPolyDraw */
7959 NULL
, /* pPolyPolygon */
7960 NULL
, /* pPolyPolyline */
7961 NULL
, /* pPolygon */
7962 NULL
, /* pPolyline */
7963 NULL
, /* pPolylineTo */
7964 NULL
, /* pPutImage */
7965 NULL
, /* pRealizeDefaultPalette */
7966 NULL
, /* pRealizePalette */
7967 NULL
, /* pRectangle */
7968 NULL
, /* pResetDC */
7969 NULL
, /* pRestoreDC */
7970 NULL
, /* pRoundRect */
7972 NULL
, /* pScaleViewportExt */
7973 NULL
, /* pScaleWindowExt */
7974 NULL
, /* pSelectBitmap */
7975 NULL
, /* pSelectBrush */
7976 NULL
, /* pSelectClipPath */
7977 freetype_SelectFont
, /* pSelectFont */
7978 NULL
, /* pSelectPalette */
7979 NULL
, /* pSelectPen */
7980 NULL
, /* pSetArcDirection */
7981 NULL
, /* pSetBkColor */
7982 NULL
, /* pSetBkMode */
7983 NULL
, /* pSetDCBrushColor */
7984 NULL
, /* pSetDCPenColor */
7985 NULL
, /* pSetDIBColorTable */
7986 NULL
, /* pSetDIBitsToDevice */
7987 NULL
, /* pSetDeviceClipping */
7988 NULL
, /* pSetDeviceGammaRamp */
7989 NULL
, /* pSetLayout */
7990 NULL
, /* pSetMapMode */
7991 NULL
, /* pSetMapperFlags */
7992 NULL
, /* pSetPixel */
7993 NULL
, /* pSetPolyFillMode */
7994 NULL
, /* pSetROP2 */
7995 NULL
, /* pSetRelAbs */
7996 NULL
, /* pSetStretchBltMode */
7997 NULL
, /* pSetTextAlign */
7998 NULL
, /* pSetTextCharacterExtra */
7999 NULL
, /* pSetTextColor */
8000 NULL
, /* pSetTextJustification */
8001 NULL
, /* pSetViewportExt */
8002 NULL
, /* pSetViewportOrg */
8003 NULL
, /* pSetWindowExt */
8004 NULL
, /* pSetWindowOrg */
8005 NULL
, /* pSetWorldTransform */
8006 NULL
, /* pStartDoc */
8007 NULL
, /* pStartPage */
8008 NULL
, /* pStretchBlt */
8009 NULL
, /* pStretchDIBits */
8010 NULL
, /* pStrokeAndFillPath */
8011 NULL
, /* pStrokePath */
8012 NULL
, /* pUnrealizePalette */
8013 NULL
, /* pWidenPath */
8014 NULL
, /* wine_get_wgl_driver */
8015 GDI_PRIORITY_FONT_DRV
/* priority */
8018 #else /* HAVE_FREETYPE */
8020 /*************************************************************************/
8022 BOOL
WineEngInit(void)
8027 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8029 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8033 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8035 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8039 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8041 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8045 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8046 LPCWSTR font_file
, LPCWSTR font_path
)
8052 /*************************************************************************
8053 * GetRasterizerCaps (GDI32.@)
8055 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8057 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8059 lprs
->nLanguageID
= 0;
8063 #endif /* HAVE_FREETYPE */