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
;
357 const VOID
*vert_feature
;
363 const WCHAR
*font_name
;
368 struct enum_charset_element
{
371 WCHAR name
[LF_FACESIZE
];
374 struct enum_charset_list
{
376 struct enum_charset_element element
[32];
379 #define GM_BLOCK_SIZE 128
380 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
382 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
383 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
384 static unsigned int unused_font_count
;
385 #define UNUSED_CACHE_SIZE 10
386 static struct list system_links
= LIST_INIT(system_links
);
388 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
390 static struct list font_list
= LIST_INIT(font_list
);
392 struct freetype_physdev
394 struct gdi_physdev dev
;
398 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
400 return (struct freetype_physdev
*)dev
;
403 static const struct gdi_dc_funcs freetype_funcs
;
405 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
406 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
407 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
409 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
410 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
411 'W','i','n','d','o','w','s','\\',
412 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
413 'F','o','n','t','s','\0'};
415 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
416 'W','i','n','d','o','w','s',' ','N','T','\\',
417 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
418 'F','o','n','t','s','\0'};
420 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
421 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
422 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
423 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
425 static const WCHAR
* const SystemFontValues
[] = {
432 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
433 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
435 /* Interesting and well-known (frequently-assumed!) font names */
436 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
437 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 };
438 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
439 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
440 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
441 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
442 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
443 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
445 static const WCHAR arial
[] = {'A','r','i','a','l',0};
446 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
447 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};
448 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};
449 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
450 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
451 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
452 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
453 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
454 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
456 static const WCHAR
*default_serif_list
[] =
460 bitstream_vera_serif
,
464 static const WCHAR
*default_fixed_list
[] =
468 bitstream_vera_sans_mono
,
472 static const WCHAR
*default_sans_list
[] =
485 typedef struct tagFontSubst
{
491 /* Registry font cache key and value names */
492 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
493 'F','o','n','t','s',0};
494 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
495 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
496 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
497 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
498 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
499 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
500 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
501 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
502 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
503 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
504 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
505 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
506 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
507 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
508 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
521 static struct list mappings_list
= LIST_INIT( mappings_list
);
523 static UINT default_aa_flags
;
524 static HKEY hkey_font_cache
;
526 static CRITICAL_SECTION freetype_cs
;
527 static CRITICAL_SECTION_DEBUG critsect_debug
=
530 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
531 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
533 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
535 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
537 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
538 static BOOL use_default_fallback
= FALSE
;
540 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
541 static BOOL
get_outline_text_metrics(GdiFont
*font
);
542 static BOOL
get_bitmap_text_metrics(GdiFont
*font
);
543 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
544 static void remove_face_from_cache( Face
*face
);
546 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
547 'W','i','n','d','o','w','s',' ','N','T','\\',
548 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
549 'S','y','s','t','e','m','L','i','n','k',0};
551 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
552 'F','o','n','t','L','i','n','k','\\',
553 'S','y','s','t','e','m','L','i','n','k',0};
555 /****************************************
556 * Notes on .fon files
558 * The fonts System, FixedSys and Terminal are special. There are typically multiple
559 * versions installed for different resolutions and codepages. Windows stores which one to use
560 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
562 * FIXEDFON.FON FixedSys
564 * OEMFONT.FON Terminal
565 * LogPixels Current dpi set by the display control panel applet
566 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
567 * also has a LogPixels value that appears to mirror this)
569 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
570 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
571 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
572 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
573 * so that makes sense.
575 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
576 * to be mapped into the registry on Windows 2000 at least).
579 * ega80woa.fon=ega80850.fon
580 * ega40woa.fon=ega40850.fon
581 * cga80woa.fon=cga80850.fon
582 * cga40woa.fon=cga40850.fon
585 /* These are all structures needed for the GSUB table */
587 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
588 #define TATEGAKI_LOWER_BOUND 0x02F1
604 GSUB_ScriptRecord ScriptRecord
[1];
610 } GSUB_LangSysRecord
;
615 GSUB_LangSysRecord LangSysRecord
[1];
619 WORD LookupOrder
; /* Reserved */
620 WORD ReqFeatureIndex
;
622 WORD FeatureIndex
[1];
628 } GSUB_FeatureRecord
;
632 GSUB_FeatureRecord FeatureRecord
[1];
636 WORD FeatureParams
; /* Reserved */
638 WORD LookupListIndex
[1];
657 } GSUB_CoverageFormat1
;
662 WORD StartCoverageIndex
;
668 GSUB_RangeRecord RangeRecord
[1];
669 } GSUB_CoverageFormat2
;
672 WORD SubstFormat
; /* = 1 */
675 } GSUB_SingleSubstFormat1
;
678 WORD SubstFormat
; /* = 2 */
682 }GSUB_SingleSubstFormat2
;
684 #ifdef HAVE_CARBON_CARBON_H
685 static char *find_cache_dir(void)
689 static char cached_path
[MAX_PATH
];
690 static const char *wine
= "/Wine", *fonts
= "/Fonts";
692 if(*cached_path
) return cached_path
;
694 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
697 WARN("can't create cached data folder\n");
700 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
703 WARN("can't create cached data path\n");
707 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
709 ERR("Could not create full path\n");
713 strcat(cached_path
, wine
);
715 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
717 WARN("Couldn't mkdir %s\n", cached_path
);
721 strcat(cached_path
, fonts
);
722 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
724 WARN("Couldn't mkdir %s\n", cached_path
);
731 /******************************************************************
734 * Extracts individual TrueType font files from a Mac suitcase font
735 * and saves them into the user's caches directory (see
737 * Returns a NULL terminated array of filenames.
739 * We do this because they are apps that try to read ttf files
740 * themselves and they don't like Mac suitcase files.
742 static char **expand_mac_font(const char *path
)
749 const char *filename
;
753 unsigned int size
, max_size
;
756 TRACE("path %s\n", path
);
758 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
761 WARN("failed to get ref\n");
765 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
768 TRACE("no data fork, so trying resource fork\n");
769 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
772 TRACE("unable to open resource fork\n");
779 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
782 CloseResFile(res_ref
);
786 out_dir
= find_cache_dir();
788 filename
= strrchr(path
, '/');
789 if(!filename
) filename
= path
;
792 /* output filename has the form out_dir/filename_%04x.ttf */
793 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
800 unsigned short *num_faces_ptr
, num_faces
, face
;
803 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
805 fond
= Get1IndResource(fond_res
, idx
);
807 TRACE("got fond resource %d\n", idx
);
810 fam_rec
= *(FamRec
**)fond
;
811 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
812 num_faces
= GET_BE_WORD(*num_faces_ptr
);
814 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
815 TRACE("num faces %04x\n", num_faces
);
816 for(face
= 0; face
< num_faces
; face
++, assoc
++)
819 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
820 unsigned short size
, font_id
;
823 size
= GET_BE_WORD(assoc
->fontSize
);
824 font_id
= GET_BE_WORD(assoc
->fontID
);
827 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
831 TRACE("trying to load sfnt id %04x\n", font_id
);
832 sfnt
= GetResource(sfnt_res
, font_id
);
835 TRACE("can't get sfnt resource %04x\n", font_id
);
839 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
844 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
846 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
847 if(fd
!= -1 || errno
== EEXIST
)
851 unsigned char *sfnt_data
;
854 sfnt_data
= *(unsigned char**)sfnt
;
855 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
859 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
862 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
864 ret
.array
[ret
.size
++] = output
;
868 WARN("unable to create %s\n", output
);
869 HeapFree(GetProcessHeap(), 0, output
);
872 ReleaseResource(sfnt
);
875 ReleaseResource(fond
);
878 CloseResFile(res_ref
);
883 #endif /* HAVE_CARBON_CARBON_H */
885 static inline BOOL
is_win9x(void)
887 return GetVersion() & 0x80000000;
890 This function builds an FT_Fixed from a double. It fails if the absolute
891 value of the float number is greater than 32768.
893 static inline FT_Fixed
FT_FixedFromFloat(double f
)
899 This function builds an FT_Fixed from a FIXED. It simply put f.value
900 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
902 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
904 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
907 static BOOL
is_hinting_enabled(void)
909 static int enabled
= -1;
913 /* Use the >= 2.2.0 function if available */
914 if (pFT_Get_TrueType_Engine_Type
)
916 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
917 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
919 #ifdef FT_DRIVER_HAS_HINTER
922 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
923 FT_Module mod
= pFT_Get_Module(library
, "truetype");
924 enabled
= (mod
&& FT_DRIVER_HAS_HINTER(mod
));
927 else enabled
= FALSE
;
928 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
933 static BOOL
is_subpixel_rendering_enabled( void )
935 #ifdef HAVE_FREETYPE_FTLCDFIL_H
936 static int enabled
= -1;
939 enabled
= (pFT_Library_SetLcdFilter
&&
940 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
941 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
950 static const struct list
*get_face_list_from_family(const Family
*family
)
952 if (!list_empty(&family
->faces
))
953 return &family
->faces
;
955 return family
->replacement
;
958 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
964 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
966 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
968 const struct list
*face_list
;
969 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
971 face_list
= get_face_list_from_family(family
);
972 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
976 file
= strrchrW(face
->file
, '/');
981 if(strcmpiW(file
, file_name
)) continue;
989 static Family
*find_family_from_name(const WCHAR
*name
)
993 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
995 if(!strcmpiW(family
->FamilyName
, name
))
1002 static Family
*find_family_from_any_name(const WCHAR
*name
)
1006 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1008 if(!strcmpiW(family
->FamilyName
, name
))
1010 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1017 static void DumpSubstList(void)
1021 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1023 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1024 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1025 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1027 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1028 debugstr_w(psub
->to
.name
));
1033 static LPWSTR
strdupW(LPCWSTR p
)
1036 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1037 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1038 memcpy(ret
, p
, len
);
1042 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1047 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1049 if(!strcmpiW(element
->from
.name
, from_name
) &&
1050 (element
->from
.charset
== from_charset
||
1051 element
->from
.charset
== -1))
1058 #define ADD_FONT_SUBST_FORCE 1
1060 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1062 FontSubst
*from_exist
, *to_exist
;
1064 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1066 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1068 list_remove(&from_exist
->entry
);
1069 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1070 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1071 HeapFree(GetProcessHeap(), 0, from_exist
);
1077 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1081 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1082 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1085 list_add_tail(subst_list
, &subst
->entry
);
1090 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1091 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1092 HeapFree(GetProcessHeap(), 0, subst
);
1096 static WCHAR
*towstr(UINT cp
, const char *str
)
1101 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1102 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1103 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1107 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1109 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1110 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1111 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1115 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1117 CHAR
*p
= strrchr(str
, ',');
1121 nc
->charset
= strtol(p
+1, NULL
, 10);
1124 nc
->name
= towstr(CP_ACP
, str
);
1127 static void LoadSubstList(void)
1131 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1135 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1136 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1137 &hkey
) == ERROR_SUCCESS
) {
1139 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1140 &valuelen
, &datalen
, NULL
, NULL
);
1142 valuelen
++; /* returned value doesn't include room for '\0' */
1143 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1144 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1148 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1149 &dlen
) == ERROR_SUCCESS
) {
1150 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1152 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1153 split_subst_info(&psub
->from
, value
);
1154 split_subst_info(&psub
->to
, data
);
1156 /* Win 2000 doesn't allow mapping between different charsets
1157 or mapping of DEFAULT_CHARSET */
1158 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1159 psub
->to
.charset
== DEFAULT_CHARSET
) {
1160 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1161 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1162 HeapFree(GetProcessHeap(), 0, psub
);
1164 add_font_subst(&font_subst_list
, psub
, 0);
1166 /* reset dlen and vlen */
1170 HeapFree(GetProcessHeap(), 0, data
);
1171 HeapFree(GetProcessHeap(), 0, value
);
1177 /*****************************************************************
1178 * get_name_table_entry
1180 * Supply the platform, encoding, language and name ids in req
1181 * and if the name exists the function will fill in the string
1182 * and string_len members. The string is owned by FreeType so
1183 * don't free it. Returns TRUE if the name is found else FALSE.
1185 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1188 FT_UInt num_names
, name_index
;
1190 if(FT_IS_SFNT(ft_face
))
1192 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1194 for(name_index
= 0; name_index
< num_names
; name_index
++)
1196 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1198 if((name
.platform_id
== req
->platform_id
) &&
1199 ((name
.encoding_id
== TT_MS_ID_UNICODE_CS
) || (name
.encoding_id
== TT_MS_ID_SYMBOL_CS
)) &&
1200 (name
.language_id
== req
->language_id
) &&
1201 (name
.name_id
== req
->name_id
))
1203 req
->string
= name
.string
;
1204 req
->string_len
= name
.string_len
;
1211 req
->string_len
= 0;
1215 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1220 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1221 name
.language_id
= language_id
;
1222 name
.name_id
= name_id
;
1224 if(get_name_table_entry(ft_face
, &name
))
1228 /* String is not nul terminated and string_len is a byte length. */
1229 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1230 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1232 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1233 ret
[i
] = GET_BE_WORD(*tmp
);
1236 TRACE("Got localised name %s\n", debugstr_w(ret
));
1242 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1244 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1245 if (f1
->scalable
) return TRUE
;
1246 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1247 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1250 static void release_family( Family
*family
)
1252 if (--family
->refcount
) return;
1253 assert( list_empty( &family
->faces
));
1254 list_remove( &family
->entry
);
1255 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1256 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1257 HeapFree( GetProcessHeap(), 0, family
);
1260 static void release_face( Face
*face
)
1262 if (--face
->refcount
) return;
1265 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1266 list_remove( &face
->entry
);
1267 release_family( face
->family
);
1269 HeapFree( GetProcessHeap(), 0, face
->file
);
1270 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1271 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1272 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1273 HeapFree( GetProcessHeap(), 0, face
);
1276 static inline int style_order(const Face
*face
)
1278 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1286 case NTM_BOLD
| NTM_ITALIC
:
1289 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1290 debugstr_w(face
->family
->FamilyName
),
1291 debugstr_w(face
->StyleName
),
1297 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1301 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1303 if (faces_equal( face
, cursor
))
1305 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1306 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1307 cursor
->font_version
, face
->font_version
);
1309 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1312 TRACE("Font %s already in list, refcount now %d\n",
1313 debugstr_w(face
->file
), cursor
->refcount
);
1316 if (face
->font_version
<= cursor
->font_version
)
1318 TRACE("Original font %s is newer so skipping %s\n",
1319 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1324 TRACE("Replacing original %s with %s\n",
1325 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1326 list_add_before( &cursor
->entry
, &face
->entry
);
1327 face
->family
= family
;
1330 release_face( cursor
);
1335 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1337 if (style_order( face
) < style_order( cursor
)) break;
1340 list_add_before( &cursor
->entry
, &face
->entry
);
1341 face
->family
= family
;
1347 /****************************************************************
1348 * NB This function stores the ptrs to the strings to save copying.
1349 * Don't free them after calling.
1351 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1353 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1354 family
->refcount
= 1;
1355 family
->FamilyName
= name
;
1356 family
->EnglishName
= english_name
;
1357 list_init( &family
->faces
);
1358 family
->replacement
= &family
->faces
;
1359 list_add_tail( &font_list
, &family
->entry
);
1364 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1366 DWORD type
, size
= sizeof(DWORD
);
1368 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1369 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1372 return ERROR_BAD_CONFIGURATION
;
1374 return ERROR_SUCCESS
;
1377 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1379 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1382 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1384 DWORD needed
, strike_index
= 0;
1387 /* If we have a File Name key then this is a real font, not just the parent
1388 key of a bunch of non-scalable strikes */
1389 needed
= buffer_size
;
1390 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1393 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1394 face
->cached_enum_data
= NULL
;
1395 face
->family
= NULL
;
1398 face
->file
= strdupW( buffer
);
1399 face
->StyleName
= strdupW(face_name
);
1401 needed
= buffer_size
;
1402 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1403 face
->FullName
= strdupW( buffer
);
1405 face
->FullName
= NULL
;
1407 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1408 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1409 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1410 reg_load_dword(hkey_face
, face_flags_value
, (DWORD
*)&face
->flags
);
1412 needed
= sizeof(face
->fs
);
1413 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1415 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1417 face
->scalable
= TRUE
;
1418 memset(&face
->size
, 0, sizeof(face
->size
));
1422 face
->scalable
= FALSE
;
1423 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1424 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1425 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1426 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1427 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1429 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1430 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1431 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1434 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1435 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1436 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1437 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1439 if (insert_face_in_family_list(face
, family
))
1440 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1442 release_face( face
);
1445 /* load bitmap strikes */
1447 needed
= buffer_size
;
1448 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1450 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1452 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1453 RegCloseKey(hkey_strike
);
1455 needed
= buffer_size
;
1459 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1461 DWORD size
, family_index
= 0;
1466 size
= sizeof(buffer
);
1467 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1469 WCHAR
*english_family
= NULL
;
1470 WCHAR
*family_name
= strdupW( buffer
);
1471 DWORD face_index
= 0;
1473 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1474 TRACE("opened family key %s\n", debugstr_w(family_name
));
1475 size
= sizeof(buffer
);
1476 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1477 english_family
= strdupW( buffer
);
1479 family
= create_family(family_name
, english_family
);
1483 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1484 subst
->from
.name
= strdupW(english_family
);
1485 subst
->from
.charset
= -1;
1486 subst
->to
.name
= strdupW(family_name
);
1487 subst
->to
.charset
= -1;
1488 add_font_subst(&font_subst_list
, subst
, 0);
1491 size
= sizeof(buffer
);
1492 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1494 WCHAR
*face_name
= strdupW( buffer
);
1497 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1499 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1500 RegCloseKey(hkey_face
);
1502 HeapFree( GetProcessHeap(), 0, face_name
);
1503 size
= sizeof(buffer
);
1505 RegCloseKey(hkey_family
);
1506 release_family( family
);
1507 size
= sizeof(buffer
);
1511 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1514 HKEY hkey_wine_fonts
;
1516 /* We don't want to create the fonts key as volatile, so open this first */
1517 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1518 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1519 if(ret
!= ERROR_SUCCESS
)
1521 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1525 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1526 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1527 RegCloseKey(hkey_wine_fonts
);
1531 static void add_face_to_cache(Face
*face
)
1533 HKEY hkey_family
, hkey_face
;
1534 WCHAR
*face_key_name
;
1536 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1537 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1538 if(face
->family
->EnglishName
)
1539 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1540 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1543 face_key_name
= face
->StyleName
;
1546 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1547 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1548 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1550 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1553 HeapFree(GetProcessHeap(), 0, face_key_name
);
1555 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1556 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1558 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1559 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1561 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1562 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1563 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1564 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1566 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1570 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1571 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1572 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1573 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1574 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1575 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1577 RegCloseKey(hkey_face
);
1578 RegCloseKey(hkey_family
);
1581 static void remove_face_from_cache( Face
*face
)
1585 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1589 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1593 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1594 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1595 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1596 RegDeleteKeyW( hkey_family
, face_key_name
);
1597 HeapFree(GetProcessHeap(), 0, face_key_name
);
1599 RegCloseKey(hkey_family
);
1602 static WCHAR
*prepend_at(WCHAR
*family
)
1609 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1611 strcpyW(str
+ 1, family
);
1612 HeapFree(GetProcessHeap(), 0, family
);
1616 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1618 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1619 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1621 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1627 else if (!strcmpiW( *name
, *english
))
1629 HeapFree( GetProcessHeap(), 0, *english
);
1635 *name
= prepend_at( *name
);
1636 *english
= prepend_at( *english
);
1640 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1643 WCHAR
*name
, *english_name
;
1645 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1647 family
= find_family_from_name( name
);
1651 family
= create_family( name
, english_name
);
1654 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1655 subst
->from
.name
= strdupW( english_name
);
1656 subst
->from
.charset
= -1;
1657 subst
->to
.name
= strdupW( name
);
1658 subst
->to
.charset
= -1;
1659 add_font_subst( &font_subst_list
, subst
, 0 );
1664 HeapFree( GetProcessHeap(), 0, name
);
1665 HeapFree( GetProcessHeap(), 0, english_name
);
1672 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1674 FT_Fixed version
= 0;
1677 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1678 if (header
) version
= header
->Font_Revision
;
1683 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1686 FT_ULong table_size
= 0;
1688 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1689 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1690 if (flags
== 0) flags
= NTM_REGULAR
;
1692 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1693 flags
|= NTM_PS_OPENTYPE
;
1698 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1700 int internal_leading
= 0;
1701 FT_WinFNT_HeaderRec winfnt_header
;
1703 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1704 internal_leading
= winfnt_header
.internal_leading
;
1706 return internal_leading
;
1709 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1714 FT_WinFNT_HeaderRec winfnt_header
;
1717 memset( fs
, 0, sizeof(*fs
) );
1719 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1722 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1723 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1724 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1725 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1727 if (os2
->version
== 0)
1729 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1730 fs
->fsCsb
[0] = FS_LATIN1
;
1732 fs
->fsCsb
[0] = FS_SYMBOL
;
1736 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1737 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1742 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1744 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1745 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1746 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1751 if (fs
->fsCsb
[0] == 0)
1753 /* let's see if we can find any interesting cmaps */
1754 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1756 switch (ft_face
->charmaps
[i
]->encoding
)
1758 case FT_ENCODING_UNICODE
:
1759 case FT_ENCODING_APPLE_ROMAN
:
1760 fs
->fsCsb
[0] |= FS_LATIN1
;
1762 case FT_ENCODING_MS_SYMBOL
:
1763 fs
->fsCsb
[0] |= FS_SYMBOL
;
1772 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1776 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1777 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1780 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1781 if (!face
->StyleName
)
1782 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1783 if (!face
->StyleName
)
1785 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1788 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1789 if (!face
->FullName
)
1790 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1791 if (flags
& ADDFONT_VERTICAL_FONT
)
1792 face
->FullName
= prepend_at( face
->FullName
);
1798 face
->file
= towstr( CP_UNIXCP
, file
);
1799 face
->font_data_ptr
= NULL
;
1800 face
->font_data_size
= 0;
1801 if (!stat( file
, &st
))
1803 face
->dev
= st
.st_dev
;
1804 face
->ino
= st
.st_ino
;
1810 face
->font_data_ptr
= font_data_ptr
;
1811 face
->font_data_size
= font_data_size
;
1814 face
->face_index
= face_index
;
1815 get_fontsig( ft_face
, &face
->fs
);
1816 face
->ntmFlags
= get_ntm_flags( ft_face
);
1817 face
->font_version
= get_font_version( ft_face
);
1819 if (FT_IS_SCALABLE( ft_face
))
1821 memset( &face
->size
, 0, sizeof(face
->size
) );
1822 face
->scalable
= TRUE
;
1826 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1827 size
->height
, size
->width
, size
->size
>> 6,
1828 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1829 face
->size
.height
= size
->height
;
1830 face
->size
.width
= size
->width
;
1831 face
->size
.size
= size
->size
;
1832 face
->size
.x_ppem
= size
->x_ppem
;
1833 face
->size
.y_ppem
= size
->y_ppem
;
1834 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1835 face
->scalable
= FALSE
;
1838 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1839 face
->flags
= flags
;
1840 face
->family
= NULL
;
1841 face
->cached_enum_data
= NULL
;
1843 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1844 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1845 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1846 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1851 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1852 FT_Long face_index
, DWORD flags
)
1857 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
1858 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
1859 if (insert_face_in_family_list( face
, family
))
1861 if (flags
& ADDFONT_ADD_TO_CACHE
)
1862 add_face_to_cache( face
);
1864 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1865 debugstr_w(face
->StyleName
));
1867 release_face( face
);
1868 release_family( family
);
1871 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1872 FT_Long face_index
, BOOL allow_bitmap
)
1880 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1881 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1885 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1886 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1891 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1895 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1896 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1898 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1902 if (!FT_IS_SFNT( ft_face
))
1904 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1906 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1912 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1913 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1914 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1916 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1917 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1921 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1922 we don't want to load these. */
1923 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1927 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1929 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1935 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1937 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1943 pFT_Done_Face( ft_face
);
1947 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1950 FT_Long face_index
= 0, num_faces
;
1953 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1954 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1956 #ifdef HAVE_CARBON_CARBON_H
1959 char **mac_list
= expand_mac_font(file
);
1962 BOOL had_one
= FALSE
;
1964 for(cursor
= mac_list
; *cursor
; cursor
++)
1967 AddFontToList(*cursor
, NULL
, 0, flags
);
1968 HeapFree(GetProcessHeap(), 0, *cursor
);
1970 HeapFree(GetProcessHeap(), 0, mac_list
);
1975 #endif /* HAVE_CARBON_CARBON_H */
1978 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
1979 if (!ft_face
) return 0;
1981 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1983 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1984 pFT_Done_Face(ft_face
);
1988 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
1991 if (FT_HAS_VERTICAL(ft_face
))
1993 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
1994 flags
| ADDFONT_VERTICAL_FONT
);
1998 num_faces
= ft_face
->num_faces
;
1999 pFT_Done_Face(ft_face
);
2000 } while(num_faces
> ++face_index
);
2004 static int remove_font_resource( const char *file
, DWORD flags
)
2006 Family
*family
, *family_next
;
2007 Face
*face
, *face_next
;
2011 if (stat( file
, &st
) == -1) return 0;
2012 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2015 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2017 if (!face
->file
) continue;
2018 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2019 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2021 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2022 release_face( face
);
2026 release_family( family
);
2031 static void DumpFontList(void)
2036 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2037 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2038 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2039 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2041 TRACE(" %d", face
->size
.height
);
2048 /***********************************************************
2049 * The replacement list is a way to map an entire font
2050 * family onto another family. For example adding
2052 * [HKCU\Software\Wine\Fonts\Replacements]
2053 * "Wingdings"="Winedings"
2055 * would enumerate the Winedings font both as Winedings and
2056 * Wingdings. However if a real Wingdings font is present the
2057 * replacement does not take place.
2060 static void LoadReplaceList(void)
2063 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2067 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2068 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2070 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2071 &valuelen
, &datalen
, NULL
, NULL
);
2073 valuelen
++; /* returned value doesn't include room for '\0' */
2074 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2075 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2079 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2080 &dlen
) == ERROR_SUCCESS
) {
2081 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2082 /* "NewName"="Oldname" */
2083 if(!find_family_from_any_name(value
))
2085 Family
* const family
= find_family_from_any_name(data
);
2088 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2089 if (new_family
!= NULL
)
2091 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2092 new_family
->FamilyName
= strdupW(value
);
2093 new_family
->EnglishName
= NULL
;
2094 list_init(&new_family
->faces
);
2095 new_family
->replacement
= &family
->faces
;
2096 list_add_tail(&font_list
, &new_family
->entry
);
2101 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2106 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2108 /* reset dlen and vlen */
2112 HeapFree(GetProcessHeap(), 0, data
);
2113 HeapFree(GetProcessHeap(), 0, value
);
2118 static const WCHAR
*font_links_list
[] =
2120 Lucida_Sans_Unicode
,
2121 Microsoft_Sans_Serif
,
2125 static const struct font_links_defaults_list
2127 /* Keyed off substitution for "MS Shell Dlg" */
2128 const WCHAR
*shelldlg
;
2129 /* Maximum of four substitutes, plus terminating NULL pointer */
2130 const WCHAR
*substitutes
[5];
2131 } font_links_defaults_list
[] =
2133 /* Non East-Asian */
2134 { Tahoma
, /* FIXME unverified ordering */
2135 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2137 /* Below lists are courtesy of
2138 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2142 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2144 /* Chinese Simplified */
2146 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2150 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2152 /* Chinese Traditional */
2154 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2159 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2161 SYSTEM_LINKS
*font_link
;
2163 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2165 if(!strcmpiW(font_link
->font_name
, name
))
2172 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2183 SYSTEM_LINKS
*font_link
;
2185 psub
= get_font_subst(&font_subst_list
, name
, -1);
2186 /* Don't store fonts that are only substitutes for other fonts */
2189 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2193 font_link
= find_font_link(name
);
2194 if (font_link
== NULL
)
2196 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2197 font_link
->font_name
= strdupW(name
);
2198 list_init(&font_link
->links
);
2199 list_add_tail(&system_links
, &font_link
->entry
);
2202 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2203 for (i
= 0; values
[i
] != NULL
; i
++)
2205 const struct list
*face_list
;
2206 CHILD_FONT
*child_font
;
2209 if (!strcmpiW(name
,value
))
2211 psub
= get_font_subst(&font_subst_list
, value
, -1);
2213 value
= psub
->to
.name
;
2214 family
= find_family_from_name(value
);
2218 /* Use first extant filename for this Family */
2219 face_list
= get_face_list_from_family(family
);
2220 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2224 file
= strrchrW(face
->file
, '/');
2233 face
= find_face_from_filename(file
, value
);
2236 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2240 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2241 child_font
->face
= face
;
2242 child_font
->font
= NULL
;
2243 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2244 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2245 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2246 child_font
->face
->face_index
);
2247 list_add_tail(&font_link
->links
, &child_font
->entry
);
2249 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2255 /*************************************************************
2258 static BOOL
init_system_links(void)
2262 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2263 WCHAR
*value
, *data
;
2264 WCHAR
*entry
, *next
;
2265 SYSTEM_LINKS
*font_link
, *system_font_link
;
2266 CHILD_FONT
*child_font
;
2267 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2268 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2269 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2274 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2276 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2277 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2278 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2279 val_len
= max_val
+ 1;
2280 data_len
= max_data
;
2282 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2284 psub
= get_font_subst(&font_subst_list
, value
, -1);
2285 /* Don't store fonts that are only substitutes for other fonts */
2288 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2291 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2292 font_link
->font_name
= strdupW(value
);
2293 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2294 list_init(&font_link
->links
);
2295 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2298 CHILD_FONT
*child_font
;
2300 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2302 next
= entry
+ strlenW(entry
) + 1;
2304 face_name
= strchrW(entry
, ',');
2308 while(isspaceW(*face_name
))
2311 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2313 face_name
= psub
->to
.name
;
2315 face
= find_face_from_filename(entry
, face_name
);
2318 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2322 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2323 child_font
->face
= face
;
2324 child_font
->font
= NULL
;
2325 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2326 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2327 TRACE("Adding file %s index %ld\n",
2328 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2329 list_add_tail(&font_link
->links
, &child_font
->entry
);
2331 list_add_tail(&system_links
, &font_link
->entry
);
2333 val_len
= max_val
+ 1;
2334 data_len
= max_data
;
2337 HeapFree(GetProcessHeap(), 0, value
);
2338 HeapFree(GetProcessHeap(), 0, data
);
2343 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2345 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2349 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2351 const FontSubst
*psub2
;
2352 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2354 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2356 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2357 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2359 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2360 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2362 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2364 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2370 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2373 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2374 system_font_link
->font_name
= strdupW(System
);
2375 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2376 list_init(&system_font_link
->links
);
2378 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2381 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2382 child_font
->face
= face
;
2383 child_font
->font
= NULL
;
2384 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2385 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2386 TRACE("Found Tahoma in %s index %ld\n",
2387 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2388 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2390 font_link
= find_font_link(Tahoma
);
2391 if (font_link
!= NULL
)
2393 CHILD_FONT
*font_link_entry
;
2394 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2396 CHILD_FONT
*new_child
;
2397 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2398 new_child
->face
= font_link_entry
->face
;
2399 new_child
->font
= NULL
;
2400 new_child
->face
->refcount
++;
2401 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2402 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2403 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2406 list_add_tail(&system_links
, &system_font_link
->entry
);
2410 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2413 struct dirent
*dent
;
2414 char path
[MAX_PATH
];
2416 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2418 dir
= opendir(dirname
);
2420 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2423 while((dent
= readdir(dir
)) != NULL
) {
2424 struct stat statbuf
;
2426 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2429 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2431 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2433 if(stat(path
, &statbuf
) == -1)
2435 WARN("Can't stat %s\n", debugstr_a(path
));
2438 if(S_ISDIR(statbuf
.st_mode
))
2439 ReadFontDir(path
, external_fonts
);
2442 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2443 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2444 AddFontToList(path
, NULL
, 0, addfont_flags
);
2451 #ifdef SONAME_LIBFONTCONFIG
2453 static BOOL fontconfig_enabled
;
2455 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2461 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2462 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2464 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2468 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2469 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2470 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2471 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2472 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2478 static void init_fontconfig(void)
2480 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2484 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2488 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2489 LOAD_FUNCPTR(FcConfigSubstitute
);
2490 LOAD_FUNCPTR(FcFontList
);
2491 LOAD_FUNCPTR(FcFontSetDestroy
);
2492 LOAD_FUNCPTR(FcInit
);
2493 LOAD_FUNCPTR(FcObjectSetAdd
);
2494 LOAD_FUNCPTR(FcObjectSetCreate
);
2495 LOAD_FUNCPTR(FcObjectSetDestroy
);
2496 LOAD_FUNCPTR(FcPatternCreate
);
2497 LOAD_FUNCPTR(FcPatternDestroy
);
2498 LOAD_FUNCPTR(FcPatternGetBool
);
2499 LOAD_FUNCPTR(FcPatternGetInteger
);
2500 LOAD_FUNCPTR(FcPatternGetString
);
2505 FcPattern
*pattern
= pFcPatternCreate();
2506 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2507 default_aa_flags
= parse_aa_pattern( pattern
);
2508 pFcPatternDestroy( pattern
);
2509 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2510 fontconfig_enabled
= TRUE
;
2514 static void load_fontconfig_fonts(void)
2523 if (!fontconfig_enabled
) return;
2525 pat
= pFcPatternCreate();
2526 os
= pFcObjectSetCreate();
2527 pFcObjectSetAdd(os
, FC_FILE
);
2528 pFcObjectSetAdd(os
, FC_SCALABLE
);
2529 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2530 pFcObjectSetAdd(os
, FC_RGBA
);
2531 fontset
= pFcFontList(NULL
, pat
, os
);
2532 if(!fontset
) return;
2533 for(i
= 0; i
< fontset
->nfont
; i
++) {
2537 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2540 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2542 /* We're just interested in OT/TT fonts for now, so this hack just
2543 picks up the scalable fonts without extensions .pf[ab] to save time
2544 loading every other font */
2546 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2548 TRACE("not scalable\n");
2552 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2553 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2555 len
= strlen( file
);
2556 if(len
< 4) continue;
2557 ext
= &file
[ len
- 3 ];
2558 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2559 AddFontToList(file
, NULL
, 0,
2560 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2562 pFcFontSetDestroy(fontset
);
2563 pFcObjectSetDestroy(os
);
2564 pFcPatternDestroy(pat
);
2567 #elif defined(HAVE_CARBON_CARBON_H)
2569 static void load_mac_font_callback(const void *value
, void *context
)
2571 CFStringRef pathStr
= value
;
2575 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2576 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2577 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2579 TRACE("font file %s\n", path
);
2580 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2582 HeapFree(GetProcessHeap(), 0, path
);
2585 static void load_mac_fonts(void)
2587 CFStringRef removeDupesKey
;
2588 CFBooleanRef removeDupesValue
;
2589 CFDictionaryRef options
;
2590 CTFontCollectionRef col
;
2592 CFMutableSetRef paths
;
2595 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2596 removeDupesValue
= kCFBooleanTrue
;
2597 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2598 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2599 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2600 if (options
) CFRelease(options
);
2603 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2607 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2611 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2615 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2618 WARN("CFSetCreateMutable failed\n");
2623 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2625 CTFontDescriptorRef desc
;
2634 desc
= CFArrayGetValueAtIndex(descs
, i
);
2636 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2637 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2638 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2639 if (!font
) continue;
2641 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2648 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2650 if (status
!= noErr
) continue;
2652 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2655 ext
= CFURLCopyPathExtension(url
);
2658 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2659 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2668 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2670 if (!path
) continue;
2672 CFSetAddValue(paths
, path
);
2678 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2684 static char *get_data_dir_path( LPCWSTR file
)
2686 char *unix_name
= NULL
;
2687 const char *data_dir
= wine_get_data_dir();
2689 if (!data_dir
) data_dir
= wine_get_build_dir();
2693 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2695 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2696 strcpy(unix_name
, data_dir
);
2697 strcat(unix_name
, "/fonts/");
2699 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2704 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2707 char *unix_name
= get_data_dir_path( file
);
2711 EnterCriticalSection( &freetype_cs
);
2712 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2713 LeaveCriticalSection( &freetype_cs
);
2714 HeapFree(GetProcessHeap(), 0, unix_name
);
2719 static char *get_winfonts_dir_path(LPCWSTR file
)
2721 static const WCHAR slashW
[] = {'\\','\0'};
2722 WCHAR windowsdir
[MAX_PATH
];
2724 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2725 strcatW(windowsdir
, fontsW
);
2726 strcatW(windowsdir
, slashW
);
2727 strcatW(windowsdir
, file
);
2728 return wine_get_unix_file_name( windowsdir
);
2731 static void load_system_fonts(void)
2734 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2735 const WCHAR
* const *value
;
2737 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2740 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2741 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2742 strcatW(windowsdir
, fontsW
);
2743 for(value
= SystemFontValues
; *value
; value
++) {
2744 dlen
= sizeof(data
);
2745 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2749 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2750 if((unixname
= wine_get_unix_file_name(pathW
))) {
2751 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2752 HeapFree(GetProcessHeap(), 0, unixname
);
2755 load_font_from_data_dir(data
);
2762 /*************************************************************
2764 * This adds registry entries for any externally loaded fonts
2765 * (fonts from fontconfig or FontDirs). It also deletes entries
2766 * of no longer existing fonts.
2769 static void update_reg_entries(void)
2771 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2777 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2779 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2780 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2781 ERR("Can't create Windows font reg key\n");
2785 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2786 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2787 ERR("Can't create Windows font reg key\n");
2791 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2792 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2793 ERR("Can't create external font reg key\n");
2797 /* enumerate the fonts and add external ones to the two keys */
2799 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2800 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2802 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
2806 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2807 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2808 strcpyW(valueW
, face
->FullName
);
2812 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2813 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2814 strcpyW(valueW
, family
->FamilyName
);
2817 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
2818 path
= wine_get_dos_file_name( buffer
);
2819 HeapFree( GetProcessHeap(), 0, buffer
);
2823 else if ((file
= strrchrW(face
->file
, '/')))
2828 len
= strlenW(file
) + 1;
2829 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2830 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2831 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2833 HeapFree(GetProcessHeap(), 0, path
);
2834 HeapFree(GetProcessHeap(), 0, valueW
);
2838 if(external_key
) RegCloseKey(external_key
);
2839 if(win9x_key
) RegCloseKey(win9x_key
);
2840 if(winnt_key
) RegCloseKey(winnt_key
);
2844 static void delete_external_font_keys(void)
2846 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2847 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2851 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2852 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2853 ERR("Can't create Windows font reg key\n");
2857 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2858 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2859 ERR("Can't create Windows font reg key\n");
2863 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2864 ERR("Can't create external font reg key\n");
2868 /* Delete all external fonts added last time */
2870 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2871 &valuelen
, &datalen
, NULL
, NULL
);
2872 valuelen
++; /* returned value doesn't include room for '\0' */
2873 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2874 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2876 dlen
= datalen
* sizeof(WCHAR
);
2879 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2880 &dlen
) == ERROR_SUCCESS
) {
2882 RegDeleteValueW(winnt_key
, valueW
);
2883 RegDeleteValueW(win9x_key
, valueW
);
2884 /* reset dlen and vlen */
2888 HeapFree(GetProcessHeap(), 0, data
);
2889 HeapFree(GetProcessHeap(), 0, valueW
);
2891 /* Delete the old external fonts key */
2892 RegCloseKey(external_key
);
2893 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2896 if(win9x_key
) RegCloseKey(win9x_key
);
2897 if(winnt_key
) RegCloseKey(winnt_key
);
2900 /*************************************************************
2901 * WineEngAddFontResourceEx
2904 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2910 if (ft_handle
) /* do it only if we have freetype up and running */
2914 EnterCriticalSection( &freetype_cs
);
2916 if((unixname
= wine_get_unix_file_name(file
)))
2918 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2920 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2921 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2922 HeapFree(GetProcessHeap(), 0, unixname
);
2924 if (!ret
&& !strchrW(file
, '\\')) {
2925 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2926 if ((unixname
= get_winfonts_dir_path( file
)))
2928 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2929 HeapFree(GetProcessHeap(), 0, unixname
);
2931 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2932 if (!ret
&& (unixname
= get_data_dir_path( file
)))
2934 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2935 HeapFree(GetProcessHeap(), 0, unixname
);
2939 LeaveCriticalSection( &freetype_cs
);
2944 /*************************************************************
2945 * WineEngAddFontMemResourceEx
2948 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2952 if (ft_handle
) /* do it only if we have freetype up and running */
2954 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2956 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2957 memcpy(pFontCopy
, pbFont
, cbFont
);
2959 EnterCriticalSection( &freetype_cs
);
2960 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2961 LeaveCriticalSection( &freetype_cs
);
2965 TRACE("AddFontToList failed\n");
2966 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2969 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2970 * For now return something unique but quite random
2972 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2973 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2980 /*************************************************************
2981 * WineEngRemoveFontResourceEx
2984 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2990 if (ft_handle
) /* do it only if we have freetype up and running */
2994 EnterCriticalSection( &freetype_cs
);
2996 if ((unixname
= wine_get_unix_file_name(file
)))
2998 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3000 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3001 ret
= remove_font_resource( unixname
, addfont_flags
);
3002 HeapFree(GetProcessHeap(), 0, unixname
);
3004 if (!ret
&& !strchrW(file
, '\\'))
3006 if ((unixname
= get_winfonts_dir_path( file
)))
3008 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3009 HeapFree(GetProcessHeap(), 0, unixname
);
3011 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3013 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3014 HeapFree(GetProcessHeap(), 0, unixname
);
3018 LeaveCriticalSection( &freetype_cs
);
3023 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3029 if (!font_file
) return NULL
;
3031 file_len
= strlenW( font_file
);
3033 if (font_path
&& font_path
[0])
3035 int path_len
= strlenW( font_path
);
3036 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3037 if (!fullname
) return NULL
;
3038 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3039 fullname
[path_len
] = '\\';
3040 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3044 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3045 if (!len
) return NULL
;
3046 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3047 if (!fullname
) return NULL
;
3048 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3051 unix_name
= wine_get_unix_file_name( fullname
);
3052 HeapFree( GetProcessHeap(), 0, fullname
);
3056 #include <pshpack1.h>
3059 WORD num_of_resources
;
3063 CHAR dfCopyright
[60];
3069 WORD dfInternalLeading
;
3070 WORD dfExternalLeading
;
3078 BYTE dfPitchAndFamily
;
3089 CHAR szFaceName
[LF_FACESIZE
];
3092 #include <poppack.h>
3094 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3095 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3097 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3099 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3101 WCHAR
*name
, *english_name
;
3103 NEWTEXTMETRICEXW ntm
;
3106 if (!ft_face
) return FALSE
;
3107 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3108 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3109 pFT_Done_Face( ft_face
);
3111 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3112 release_face( face
);
3113 HeapFree( GetProcessHeap(), 0, name
);
3114 HeapFree( GetProcessHeap(), 0, english_name
);
3116 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3118 memset( fd
, 0, sizeof(*fd
) );
3120 fd
->num_of_resources
= 1;
3122 fd
->dfVersion
= 0x200;
3123 fd
->dfSize
= sizeof(*fd
);
3124 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3125 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3126 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3128 fd
->dfHorizRes
= 72;
3129 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3130 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3131 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3132 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3133 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3134 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3135 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3136 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3138 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3139 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3140 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3141 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3142 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3143 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3144 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3145 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3146 fd
->dfWidthBytes
= 0;
3148 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3150 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3155 #define NE_FFLAGS_LIBMODULE 0x8000
3156 #define NE_OSFLAGS_WINDOWS 0x02
3158 static const char dos_string
[0x40] = "This is a TrueType resource file";
3159 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3161 #include <pshpack2.h>
3182 struct ne_typeinfo fontdir_type
;
3183 struct ne_nameinfo fontdir_name
;
3184 struct ne_typeinfo scalable_type
;
3185 struct ne_nameinfo scalable_name
;
3187 BYTE fontdir_res_name
[8];
3190 #include <poppack.h>
3192 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3196 DWORD size
, written
;
3198 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3199 char *font_fileA
, *last_part
, *ext
;
3200 IMAGE_DOS_HEADER dos
;
3201 IMAGE_OS2_HEADER ne
=
3203 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3205 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3206 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3208 struct rsrc_tab rsrc_tab
=
3212 { 0, 0, 0x0c50, 0x2c, 0 },
3214 { 0, 0, 0x0c50, 0x8001, 0 },
3216 { 7,'F','O','N','T','D','I','R'}
3219 memset( &dos
, 0, sizeof(dos
) );
3220 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3221 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3223 /* import name is last part\0, resident name is last part without extension
3224 non-resident name is "FONTRES:" + lfFaceName */
3226 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3227 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3228 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3230 last_part
= strrchr( font_fileA
, '\\' );
3231 if (last_part
) last_part
++;
3232 else last_part
= font_fileA
;
3233 import_name_len
= strlen( last_part
) + 1;
3235 ext
= strchr( last_part
, '.' );
3236 if (ext
) res_name_len
= ext
- last_part
;
3237 else res_name_len
= import_name_len
- 1;
3239 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3241 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3242 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3243 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3244 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3246 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3248 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3249 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3250 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3251 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3253 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3254 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3258 HeapFree( GetProcessHeap(), 0, font_fileA
);
3262 memcpy( ptr
, &dos
, sizeof(dos
) );
3263 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3264 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3266 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3267 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3269 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3270 *ptr
++ = res_name_len
;
3271 memcpy( ptr
, last_part
, res_name_len
);
3273 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3274 *ptr
++ = import_name_len
;
3275 memcpy( ptr
, last_part
, import_name_len
);
3277 ptr
= start
+ ne
.ne_nrestab
;
3278 *ptr
++ = non_res_name_len
;
3279 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3280 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3282 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3283 memcpy( ptr
, font_fileA
, font_file_len
);
3285 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3286 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3288 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3289 if (file
!= INVALID_HANDLE_VALUE
)
3291 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3293 CloseHandle( file
);
3296 HeapFree( GetProcessHeap(), 0, start
);
3297 HeapFree( GetProcessHeap(), 0, font_fileA
);
3302 /*************************************************************
3303 * WineEngCreateScalableFontResource
3306 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3307 LPCWSTR font_file
, LPCWSTR font_path
)
3309 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3310 struct fontdir fontdir
;
3313 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3314 SetLastError( ERROR_INVALID_PARAMETER
);
3317 if (hidden
) fontdir
.dfType
|= 0x80;
3318 ret
= create_fot( resource
, font_file
, &fontdir
);
3321 HeapFree( GetProcessHeap(), 0, unix_name
);
3325 static const struct nls_update_font_list
3327 UINT ansi_cp
, oem_cp
;
3328 const char *oem
, *fixed
, *system
;
3329 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3330 /* these are for font substitutes */
3331 const char *shelldlg
, *tmsrmn
;
3332 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3336 const char *from
, *to
;
3337 } arial_0
, courier_new_0
, times_new_roman_0
;
3338 } nls_update_font_list
[] =
3340 /* Latin 1 (United States) */
3341 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3342 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3343 "Tahoma","Times New Roman",
3344 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3347 /* Latin 1 (Multilingual) */
3348 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3349 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3350 "Tahoma","Times New Roman", /* FIXME unverified */
3351 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3354 /* Eastern Europe */
3355 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3356 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3357 "Tahoma","Times New Roman", /* FIXME unverified */
3358 "Fixedsys,238", "System,238",
3359 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3360 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3361 { "Arial CE,0", "Arial,238" },
3362 { "Courier New CE,0", "Courier New,238" },
3363 { "Times New Roman CE,0", "Times New Roman,238" }
3366 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3367 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3368 "Tahoma","Times New Roman", /* FIXME unverified */
3369 "Fixedsys,204", "System,204",
3370 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3371 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3372 { "Arial Cyr,0", "Arial,204" },
3373 { "Courier New Cyr,0", "Courier New,204" },
3374 { "Times New Roman Cyr,0", "Times New Roman,204" }
3377 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3378 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3379 "Tahoma","Times New Roman", /* FIXME unverified */
3380 "Fixedsys,161", "System,161",
3381 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3382 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3383 { "Arial Greek,0", "Arial,161" },
3384 { "Courier New Greek,0", "Courier New,161" },
3385 { "Times New Roman Greek,0", "Times New Roman,161" }
3388 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3389 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3390 "Tahoma","Times New Roman", /* FIXME unverified */
3391 "Fixedsys,162", "System,162",
3392 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3393 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3394 { "Arial Tur,0", "Arial,162" },
3395 { "Courier New Tur,0", "Courier New,162" },
3396 { "Times New Roman Tur,0", "Times New Roman,162" }
3399 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3400 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3401 "Tahoma","Times New Roman", /* FIXME unverified */
3402 "Fixedsys,177", "System,177",
3403 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3404 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3408 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3409 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3410 "Tahoma","Times New Roman", /* FIXME unverified */
3411 "Fixedsys,178", "System,178",
3412 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3413 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3417 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3418 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3419 "Tahoma","Times New Roman", /* FIXME unverified */
3420 "Fixedsys,186", "System,186",
3421 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3422 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3423 { "Arial Baltic,0", "Arial,186" },
3424 { "Courier New Baltic,0", "Courier New,186" },
3425 { "Times New Roman Baltic,0", "Times New Roman,186" }
3428 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3429 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3430 "Tahoma","Times New Roman", /* FIXME unverified */
3431 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3435 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3436 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3437 "Tahoma","Times New Roman", /* FIXME unverified */
3438 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3442 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3443 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3444 "MS UI Gothic","MS Serif",
3445 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3448 /* Chinese Simplified */
3449 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3450 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3451 "SimSun", "NSimSun",
3452 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3456 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3457 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3459 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3462 /* Chinese Traditional */
3463 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3464 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3465 "PMingLiU", "MingLiU",
3466 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3471 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3473 return ( ansi_cp
== 932 /* CP932 for Japanese */
3474 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3475 || ansi_cp
== 949 /* CP949 for Korean */
3476 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3479 static inline HKEY
create_fonts_NT_registry_key(void)
3483 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3484 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3488 static inline HKEY
create_fonts_9x_registry_key(void)
3492 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3493 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3497 static inline HKEY
create_config_fonts_registry_key(void)
3501 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3502 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3506 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3508 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3510 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3511 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3512 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3513 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3516 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3519 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3521 RegDeleteValueA(hkey
, name
);
3524 static void update_font_association_info(UINT current_ansi_codepage
)
3526 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3527 static const char *assoc_charset_subkey
= "Associated Charset";
3529 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3532 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3535 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3537 switch (current_ansi_codepage
)
3540 set_value_key(hsubkey
, "ANSI(00)", "NO");
3541 set_value_key(hsubkey
, "OEM(FF)", "NO");
3542 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3547 set_value_key(hsubkey
, "ANSI(00)", "YES");
3548 set_value_key(hsubkey
, "OEM(FF)", "YES");
3549 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3552 RegCloseKey(hsubkey
);
3555 /* TODO: Associated DefaultFonts */
3561 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3564 static void update_font_info(void)
3566 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3567 char buf
[40], cpbuf
[40];
3570 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3571 DWORD screen_dpi
= 96, font_dpi
= 0;
3574 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3575 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3576 &hkey
) == ERROR_SUCCESS
)
3578 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3582 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3585 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3587 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3588 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3589 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3590 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3591 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3593 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3594 if (is_dbcs_ansi_cp(ansi_cp
))
3595 use_default_fallback
= TRUE
;
3599 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3601 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3606 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3607 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3609 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3610 ansi_cp
, oem_cp
, screen_dpi
);
3612 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3613 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3616 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3620 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3621 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3623 hkey
= create_config_fonts_registry_key();
3624 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3625 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3626 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3629 hkey
= create_fonts_NT_registry_key();
3630 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3633 hkey
= create_fonts_9x_registry_key();
3634 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3637 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3639 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3640 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3641 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3642 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3644 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3645 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3646 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3647 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3648 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3649 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3650 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3651 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3653 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3654 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3655 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3663 /* Delete the FontSubstitutes from other locales */
3664 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3666 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3667 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3668 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3674 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3676 /* update locale dependent font association info in registry.
3677 update only when codepages changed, not logpixels. */
3678 if (strcmp(buf
, cpbuf
) != 0)
3679 update_font_association_info(ansi_cp
);
3682 static BOOL
init_freetype(void)
3684 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3687 "Wine cannot find the FreeType font library. To enable Wine to\n"
3688 "use TrueType fonts please install a version of FreeType greater than\n"
3689 "or equal to 2.0.5.\n"
3690 "http://www.freetype.org\n");
3694 #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;}
3696 LOAD_FUNCPTR(FT_Done_Face
)
3697 LOAD_FUNCPTR(FT_Get_Char_Index
)
3698 LOAD_FUNCPTR(FT_Get_First_Char
)
3699 LOAD_FUNCPTR(FT_Get_Module
)
3700 LOAD_FUNCPTR(FT_Get_Next_Char
)
3701 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3702 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3703 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3704 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3705 LOAD_FUNCPTR(FT_Init_FreeType
)
3706 LOAD_FUNCPTR(FT_Library_Version
)
3707 LOAD_FUNCPTR(FT_Load_Glyph
)
3708 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3709 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3710 #ifndef FT_MULFIX_INLINED
3711 LOAD_FUNCPTR(FT_MulFix
)
3713 LOAD_FUNCPTR(FT_New_Face
)
3714 LOAD_FUNCPTR(FT_New_Memory_Face
)
3715 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3716 LOAD_FUNCPTR(FT_Outline_Transform
)
3717 LOAD_FUNCPTR(FT_Outline_Translate
)
3718 LOAD_FUNCPTR(FT_Render_Glyph
)
3719 LOAD_FUNCPTR(FT_Select_Charmap
)
3720 LOAD_FUNCPTR(FT_Set_Charmap
)
3721 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3722 LOAD_FUNCPTR(FT_Vector_Transform
)
3723 LOAD_FUNCPTR(FT_Vector_Unit
)
3725 /* Don't warn if these ones are missing */
3726 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3727 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3728 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3731 if(pFT_Init_FreeType(&library
) != 0) {
3732 ERR("Can't init FreeType library\n");
3733 wine_dlclose(ft_handle
, NULL
, 0);
3737 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3739 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3740 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3741 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3742 ((FT_Version
.patch
) & 0x0000ff);
3744 font_driver
= &freetype_funcs
;
3749 "Wine cannot find certain functions that it needs inside the FreeType\n"
3750 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3751 "FreeType to at least version 2.1.4.\n"
3752 "http://www.freetype.org\n");
3753 wine_dlclose(ft_handle
, NULL
, 0);
3758 static void init_font_list(void)
3760 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3761 static const WCHAR pathW
[] = {'P','a','t','h',0};
3763 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3764 WCHAR windowsdir
[MAX_PATH
];
3766 const char *data_dir
;
3768 delete_external_font_keys();
3770 /* load the system bitmap fonts */
3771 load_system_fonts();
3773 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3774 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3775 strcatW(windowsdir
, fontsW
);
3776 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3778 ReadFontDir(unixname
, FALSE
);
3779 HeapFree(GetProcessHeap(), 0, unixname
);
3782 /* load the system truetype fonts */
3783 data_dir
= wine_get_data_dir();
3784 if (!data_dir
) data_dir
= wine_get_build_dir();
3785 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3787 strcpy(unixname
, data_dir
);
3788 strcat(unixname
, "/fonts/");
3789 ReadFontDir(unixname
, TRUE
);
3790 HeapFree(GetProcessHeap(), 0, unixname
);
3793 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3794 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3795 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3797 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3798 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3799 &hkey
) == ERROR_SUCCESS
)
3801 LPWSTR data
, valueW
;
3802 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3803 &valuelen
, &datalen
, NULL
, NULL
);
3805 valuelen
++; /* returned value doesn't include room for '\0' */
3806 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3807 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3810 dlen
= datalen
* sizeof(WCHAR
);
3812 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3813 &dlen
) == ERROR_SUCCESS
)
3815 if(data
[0] && (data
[1] == ':'))
3817 if((unixname
= wine_get_unix_file_name(data
)))
3819 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3820 HeapFree(GetProcessHeap(), 0, unixname
);
3823 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3825 WCHAR pathW
[MAX_PATH
];
3826 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3829 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3830 if((unixname
= wine_get_unix_file_name(pathW
)))
3832 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3833 HeapFree(GetProcessHeap(), 0, unixname
);
3836 load_font_from_data_dir(data
);
3838 /* reset dlen and vlen */
3843 HeapFree(GetProcessHeap(), 0, data
);
3844 HeapFree(GetProcessHeap(), 0, valueW
);
3848 #ifdef SONAME_LIBFONTCONFIG
3849 load_fontconfig_fonts();
3850 #elif defined(HAVE_CARBON_CARBON_H)
3854 /* then look in any directories that we've specified in the config file */
3855 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3856 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3862 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3864 len
+= sizeof(WCHAR
);
3865 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3866 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3868 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3869 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3870 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3871 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3876 LPSTR next
= strchr( ptr
, ':' );
3877 if (next
) *next
++ = 0;
3878 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3879 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3881 strcpy( unixname
, home
);
3882 strcat( unixname
, ptr
+ 1 );
3883 ReadFontDir( unixname
, TRUE
);
3884 HeapFree( GetProcessHeap(), 0, unixname
);
3887 ReadFontDir( ptr
, TRUE
);
3890 HeapFree( GetProcessHeap(), 0, valueA
);
3892 HeapFree( GetProcessHeap(), 0, valueW
);
3898 static BOOL
move_to_front(const WCHAR
*name
)
3900 Family
*family
, *cursor2
;
3901 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3903 if(!strcmpiW(family
->FamilyName
, name
))
3905 list_remove(&family
->entry
);
3906 list_add_head(&font_list
, &family
->entry
);
3913 static BOOL
set_default(const WCHAR
**name_list
)
3917 if (move_to_front(*name_list
)) return TRUE
;
3924 static void reorder_font_list(void)
3926 set_default( default_serif_list
);
3927 set_default( default_fixed_list
);
3928 set_default( default_sans_list
);
3931 /*************************************************************
3934 * Initialize FreeType library and create a list of available faces
3936 BOOL
WineEngInit(void)
3941 /* update locale dependent font info in registry */
3944 if(!init_freetype()) return FALSE
;
3946 #ifdef SONAME_LIBFONTCONFIG
3950 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3952 ERR("Failed to create font mutex\n");
3955 WaitForSingleObject(font_mutex
, INFINITE
);
3957 create_font_cache_key(&hkey_font_cache
, &disposition
);
3959 if(disposition
== REG_CREATED_NEW_KEY
)
3962 load_font_list_from_cache(hkey_font_cache
);
3964 reorder_font_list();
3971 if(disposition
== REG_CREATED_NEW_KEY
)
3972 update_reg_entries();
3974 init_system_links();
3976 ReleaseMutex(font_mutex
);
3981 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3984 TT_HoriHeader
*pHori
;
3987 const LONG MAX_PPEM
= (1 << 16) - 1;
3989 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3990 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3992 if(height
== 0) height
= 16;
3994 /* Calc. height of EM square:
3996 * For +ve lfHeight we have
3997 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3998 * Re-arranging gives:
3999 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4001 * For -ve lfHeight we have
4003 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4004 * with il = winAscent + winDescent - units_per_em]
4009 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
4010 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4011 pHori
->Ascender
- pHori
->Descender
);
4013 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4014 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
4015 if(ppem
> MAX_PPEM
) {
4016 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4020 else if(height
>= -MAX_PPEM
)
4023 WARN("Ignoring too large height %d\n", height
);
4030 static struct font_mapping
*map_font_file( const char *name
)
4032 struct font_mapping
*mapping
;
4036 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4037 if (fstat( fd
, &st
) == -1) goto error
;
4039 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4041 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4043 mapping
->refcount
++;
4048 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4051 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4054 if (mapping
->data
== MAP_FAILED
)
4056 HeapFree( GetProcessHeap(), 0, mapping
);
4059 mapping
->refcount
= 1;
4060 mapping
->dev
= st
.st_dev
;
4061 mapping
->ino
= st
.st_ino
;
4062 mapping
->size
= st
.st_size
;
4063 list_add_tail( &mappings_list
, &mapping
->entry
);
4071 static void unmap_font_file( struct font_mapping
*mapping
)
4073 if (!--mapping
->refcount
)
4075 list_remove( &mapping
->entry
);
4076 munmap( mapping
->data
, mapping
->size
);
4077 HeapFree( GetProcessHeap(), 0, mapping
);
4081 static LONG
load_VDMX(GdiFont
*, LONG
);
4083 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4090 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4094 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4095 font
->mapping
= map_font_file( filename
);
4096 HeapFree( GetProcessHeap(), 0, filename
);
4099 WARN("failed to map %s\n", debugstr_w(face
->file
));
4102 data_ptr
= font
->mapping
->data
;
4103 data_size
= font
->mapping
->size
;
4107 data_ptr
= face
->font_data_ptr
;
4108 data_size
= face
->font_data_size
;
4111 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4113 ERR("FT_New_Face rets %d\n", err
);
4117 /* set it here, as load_VDMX needs it */
4118 font
->ft_face
= ft_face
;
4120 if(FT_IS_SCALABLE(ft_face
)) {
4121 /* load the VDMX table if we have one */
4122 font
->ppem
= load_VDMX(font
, height
);
4124 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4125 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4127 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4128 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4130 font
->ppem
= height
;
4131 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4132 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4138 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4140 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4141 a single face with the requested charset. The idea is to check if
4142 the selected font supports the current ANSI codepage, if it does
4143 return the corresponding charset, else return the first charset */
4146 int acp
= GetACP(), i
;
4150 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4152 const SYSTEM_LINKS
*font_link
;
4154 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4155 return csi
.ciCharset
;
4157 font_link
= find_font_link(family_name
);
4158 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4159 return csi
.ciCharset
;
4162 for(i
= 0; i
< 32; i
++) {
4164 if(face
->fs
.fsCsb
[0] & fs0
) {
4165 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4167 return csi
.ciCharset
;
4170 FIXME("TCI failing on %x\n", fs0
);
4174 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4175 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4177 return DEFAULT_CHARSET
;
4180 static GdiFont
*alloc_font(void)
4182 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4185 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4186 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4188 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4189 ret
->total_kern_pairs
= (DWORD
)-1;
4190 ret
->kern_pairs
= NULL
;
4191 list_init(&ret
->child_fonts
);
4195 static void free_font(GdiFont
*font
)
4197 CHILD_FONT
*child
, *child_next
;
4200 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4202 list_remove(&child
->entry
);
4204 free_font(child
->font
);
4205 release_face( child
->face
);
4206 HeapFree(GetProcessHeap(), 0, child
);
4209 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4210 if (font
->mapping
) unmap_font_file( font
->mapping
);
4211 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4212 HeapFree(GetProcessHeap(), 0, font
->potm
);
4213 HeapFree(GetProcessHeap(), 0, font
->name
);
4214 for (i
= 0; i
< font
->gmsize
; i
++)
4215 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4216 HeapFree(GetProcessHeap(), 0, font
->gm
);
4217 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4218 HeapFree(GetProcessHeap(), 0, font
);
4222 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4224 FT_Face ft_face
= font
->ft_face
;
4228 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4235 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4237 /* make sure value of len is the value freetype says it needs */
4240 FT_ULong needed
= 0;
4241 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4242 if( !err
&& needed
< len
) len
= needed
;
4244 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4247 TRACE("Can't find table %c%c%c%c\n",
4248 /* bytes were reversed */
4249 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4250 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4256 /*************************************************************
4259 * load the vdmx entry for the specified height
4262 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4263 ( ( (FT_ULong)_x4 << 24 ) | \
4264 ( (FT_ULong)_x3 << 16 ) | \
4265 ( (FT_ULong)_x2 << 8 ) | \
4268 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4283 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4287 BYTE devXRatio
, devYRatio
;
4288 USHORT numRecs
, numRatios
;
4289 DWORD result
, offset
= -1;
4293 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4295 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4298 /* FIXME: need the real device aspect ratio */
4302 numRecs
= GET_BE_WORD(hdr
[1]);
4303 numRatios
= GET_BE_WORD(hdr
[2]);
4305 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4306 for(i
= 0; i
< numRatios
; i
++) {
4309 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4310 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4313 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4315 if((ratio
.xRatio
== 0 &&
4316 ratio
.yStartRatio
== 0 &&
4317 ratio
.yEndRatio
== 0) ||
4318 (devXRatio
== ratio
.xRatio
&&
4319 devYRatio
>= ratio
.yStartRatio
&&
4320 devYRatio
<= ratio
.yEndRatio
))
4322 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4323 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4324 offset
= GET_BE_WORD(tmp
);
4330 FIXME("No suitable ratio found\n");
4334 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4336 BYTE startsz
, endsz
;
4339 recs
= GET_BE_WORD(group
.recs
);
4340 startsz
= group
.startsz
;
4341 endsz
= group
.endsz
;
4343 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4345 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4346 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4347 if(result
== GDI_ERROR
) {
4348 FIXME("Failed to retrieve vTable\n");
4353 for(i
= 0; i
< recs
; i
++) {
4354 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4355 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4356 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4358 if(yMax
+ -yMin
== height
) {
4361 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4364 if(yMax
+ -yMin
> height
) {
4367 goto end
; /* failed */
4369 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4370 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4371 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4372 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4378 TRACE("ppem not found for height %d\n", height
);
4382 HeapFree(GetProcessHeap(), 0, vTable
);
4388 static void dump_gdi_font_list(void)
4392 TRACE("---------- Font Cache ----------\n");
4393 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4394 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4395 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4398 static void grab_font( GdiFont
*font
)
4400 if (!font
->refcount
++)
4402 list_remove( &font
->unused_entry
);
4403 unused_font_count
--;
4407 static void release_font( GdiFont
*font
)
4410 if (!--font
->refcount
)
4412 TRACE( "font %p\n", font
);
4414 /* add it to the unused list */
4415 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4416 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4418 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4419 TRACE( "freeing %p\n", font
);
4420 list_remove( &font
->entry
);
4421 list_remove( &font
->unused_entry
);
4424 else unused_font_count
++;
4426 if (TRACE_ON(font
)) dump_gdi_font_list();
4430 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4432 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4433 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4434 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4435 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4436 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4439 static void calc_hash(FONT_DESC
*pfd
)
4441 DWORD hash
= 0, *ptr
, two_chars
;
4445 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4447 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4449 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4451 pwc
= (WCHAR
*)&two_chars
;
4453 *pwc
= toupperW(*pwc
);
4455 *pwc
= toupperW(*pwc
);
4459 hash
^= !pfd
->can_use_bitmap
;
4464 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4471 fd
.can_use_bitmap
= can_use_bitmap
;
4474 /* try the in-use list */
4475 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4477 if(fontcmp(ret
, &fd
)) continue;
4478 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4479 list_remove( &ret
->entry
);
4480 list_add_head( &gdi_font_list
, &ret
->entry
);
4487 static void add_to_cache(GdiFont
*font
)
4489 static DWORD cache_num
= 1;
4491 font
->cache_num
= cache_num
++;
4492 list_add_head(&gdi_font_list
, &font
->entry
);
4493 TRACE( "font %p\n", font
);
4496 /*************************************************************
4497 * create_child_font_list
4499 static BOOL
create_child_font_list(GdiFont
*font
)
4502 SYSTEM_LINKS
*font_link
;
4503 CHILD_FONT
*font_link_entry
, *new_child
;
4507 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4508 font_name
= psub
? psub
->to
.name
: font
->name
;
4509 font_link
= find_font_link(font_name
);
4510 if (font_link
!= NULL
)
4512 TRACE("found entry in system list\n");
4513 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4515 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4516 new_child
->face
= font_link_entry
->face
;
4517 new_child
->font
= NULL
;
4518 new_child
->face
->refcount
++;
4519 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4520 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4525 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4526 * Sans Serif. This is how asian windows get default fallbacks for fonts
4528 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4529 font
->charset
!= OEM_CHARSET
&&
4530 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4532 font_link
= find_font_link(szDefaultFallbackLink
);
4533 if (font_link
!= NULL
)
4535 TRACE("found entry in default fallback list\n");
4536 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4538 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4539 new_child
->face
= font_link_entry
->face
;
4540 new_child
->font
= NULL
;
4541 new_child
->face
->refcount
++;
4542 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4543 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4552 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4554 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4556 if (pFT_Set_Charmap
)
4559 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4561 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4563 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4565 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4567 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4568 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4570 switch (ft_face
->charmaps
[i
]->platform_id
)
4573 cmap_def
= ft_face
->charmaps
[i
];
4575 case 0: /* Apple Unicode */
4576 cmap0
= ft_face
->charmaps
[i
];
4578 case 1: /* Macintosh */
4579 cmap1
= ft_face
->charmaps
[i
];
4582 cmap2
= ft_face
->charmaps
[i
];
4584 case 3: /* Microsoft */
4585 cmap3
= ft_face
->charmaps
[i
];
4590 if (cmap3
) /* prefer Microsoft cmap table */
4591 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4593 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4595 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4597 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4599 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4601 return ft_err
== FT_Err_Ok
;
4604 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4608 /*************************************************************
4611 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4612 LPCWSTR output
, const DEVMODEW
*devmode
)
4614 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4616 if (!physdev
) return FALSE
;
4617 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4622 /*************************************************************
4625 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4627 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4628 release_font( physdev
->font
);
4629 HeapFree( GetProcessHeap(), 0, physdev
);
4633 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4635 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4636 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4637 const FT_Encoding
*encs
= regular_order
;
4639 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4643 if (select_charmap( face
, *encs
)) break;
4649 #define GASP_GRIDFIT 0x01
4650 #define GASP_DOGRAY 0x02
4651 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4653 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4656 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4657 WORD
*alloced
= NULL
, *ptr
= buf
;
4658 WORD num_recs
, version
;
4662 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4663 if (size
== GDI_ERROR
) return FALSE
;
4664 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4665 if (size
> sizeof(buf
))
4667 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4668 if (!ptr
) return FALSE
;
4671 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4673 version
= GET_BE_WORD( *ptr
++ );
4674 num_recs
= GET_BE_WORD( *ptr
++ );
4676 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4678 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4684 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4685 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4688 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4692 HeapFree( GetProcessHeap(), 0, alloced
);
4696 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4698 const GSUB_ScriptList
*script
;
4699 const GSUB_Script
*deflt
= NULL
;
4701 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4703 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4704 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4706 const GSUB_Script
*scr
;
4709 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4710 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4712 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4714 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4720 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4724 const GSUB_LangSys
*Lang
;
4726 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4728 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4730 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4731 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4733 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4736 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4739 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4745 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4748 const GSUB_FeatureList
*feature
;
4749 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4751 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4752 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4754 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4755 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4757 const GSUB_Feature
*feat
;
4758 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4765 static const char* get_opentype_script(const GdiFont
*font
)
4768 * I am not sure if this is the correct way to generate our script tag
4771 switch (font
->charset
)
4773 case ANSI_CHARSET
: return "latn";
4774 case BALTIC_CHARSET
: return "latn"; /* ?? */
4775 case CHINESEBIG5_CHARSET
: return "hani";
4776 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4777 case GB2312_CHARSET
: return "hani";
4778 case GREEK_CHARSET
: return "grek";
4779 case HANGUL_CHARSET
: return "hang";
4780 case RUSSIAN_CHARSET
: return "cyrl";
4781 case SHIFTJIS_CHARSET
: return "kana";
4782 case TURKISH_CHARSET
: return "latn"; /* ?? */
4783 case VIETNAMESE_CHARSET
: return "latn";
4784 case JOHAB_CHARSET
: return "latn"; /* ?? */
4785 case ARABIC_CHARSET
: return "arab";
4786 case HEBREW_CHARSET
: return "hebr";
4787 case THAI_CHARSET
: return "thai";
4788 default: return "latn";
4792 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
4794 const GSUB_Header
*header
;
4795 const GSUB_Script
*script
;
4796 const GSUB_LangSys
*language
;
4797 const GSUB_Feature
*feature
;
4799 if (!font
->GSUB_Table
)
4802 header
= font
->GSUB_Table
;
4804 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4807 TRACE("Script not found\n");
4810 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
4813 TRACE("Language not found\n");
4816 feature
= GSUB_get_feature(header
, language
, "vrt2");
4818 feature
= GSUB_get_feature(header
, language
, "vert");
4821 TRACE("vrt2/vert feature not found\n");
4827 /*************************************************************
4828 * freetype_SelectFont
4830 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4832 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4834 Face
*face
, *best
, *best_bitmap
;
4835 Family
*family
, *last_resort_family
;
4836 const struct list
*face_list
;
4837 INT height
, width
= 0;
4838 unsigned int score
= 0, new_score
;
4839 signed int diff
= 0, newdiff
;
4840 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4844 FontSubst
*psub
= NULL
;
4845 DC
*dc
= get_dc_ptr( dev
->hdc
);
4846 const SYSTEM_LINKS
*font_link
;
4848 if (!hfont
) /* notification that the font has been changed by another driver */
4850 release_font( physdev
->font
);
4851 physdev
->font
= NULL
;
4852 release_dc_ptr( dc
);
4856 GetObjectW( hfont
, sizeof(lf
), &lf
);
4857 lf
.lfWidth
= abs(lf
.lfWidth
);
4859 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4861 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4862 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4863 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4866 if(dc
->GraphicsMode
== GM_ADVANCED
)
4868 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4869 /* Try to avoid not necessary glyph transformations */
4870 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4872 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4873 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4874 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4879 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4880 font scaling abilities. */
4881 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4882 dcmat
.eM21
= dcmat
.eM12
= 0;
4883 lf
.lfOrientation
= lf
.lfEscapement
;
4884 if (dc
->vport2WorldValid
)
4886 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4887 lf
.lfOrientation
= -lf
.lfOrientation
;
4888 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4889 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4893 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4894 dcmat
.eM21
, dcmat
.eM22
);
4897 EnterCriticalSection( &freetype_cs
);
4899 /* check the cache first */
4900 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4901 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4905 TRACE("not in cache\n");
4908 ret
->font_desc
.matrix
= dcmat
;
4909 ret
->font_desc
.lf
= lf
;
4910 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4911 calc_hash(&ret
->font_desc
);
4913 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4914 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4915 original value lfCharSet. Note this is a special case for
4916 Symbol and doesn't happen at least for "Wingdings*" */
4918 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4919 lf
.lfCharSet
= SYMBOL_CHARSET
;
4921 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4922 switch(lf
.lfCharSet
) {
4923 case DEFAULT_CHARSET
:
4924 csi
.fs
.fsCsb
[0] = 0;
4927 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4928 csi
.fs
.fsCsb
[0] = 0;
4934 if(lf
.lfFaceName
[0] != '\0') {
4935 CHILD_FONT
*font_link_entry
;
4936 LPWSTR FaceName
= lf
.lfFaceName
;
4938 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4941 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4942 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4943 if (psub
->to
.charset
!= -1)
4944 lf
.lfCharSet
= psub
->to
.charset
;
4947 /* We want a match on name and charset or just name if
4948 charset was DEFAULT_CHARSET. If the latter then
4949 we fixup the returned charset later in get_nearest_charset
4950 where we'll either use the charset of the current ansi codepage
4951 or if that's unavailable the first charset that the font supports.
4953 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4954 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4955 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4957 font_link
= find_font_link(family
->FamilyName
);
4958 face_list
= get_face_list_from_family(family
);
4959 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4960 if (!(face
->scalable
|| can_use_bitmap
))
4962 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4964 if (font_link
!= NULL
&&
4965 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4967 if (!csi
.fs
.fsCsb
[0])
4973 /* Search by full face name. */
4974 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4975 face_list
= get_face_list_from_family(family
);
4976 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4977 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4978 (face
->scalable
|| can_use_bitmap
))
4980 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4982 font_link
= find_font_link(family
->FamilyName
);
4983 if (font_link
!= NULL
&&
4984 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4991 * Try check the SystemLink list first for a replacement font.
4992 * We may find good replacements there.
4994 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4996 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4997 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4999 TRACE("found entry in system list\n");
5000 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5002 const SYSTEM_LINKS
*links
;
5004 face
= font_link_entry
->face
;
5005 if (!(face
->scalable
|| can_use_bitmap
))
5007 family
= face
->family
;
5008 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5010 links
= find_font_link(family
->FamilyName
);
5011 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5018 psub
= NULL
; /* substitution is no more relevant */
5020 /* If requested charset was DEFAULT_CHARSET then try using charset
5021 corresponding to the current ansi codepage */
5022 if (!csi
.fs
.fsCsb
[0])
5025 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5026 FIXME("TCI failed on codepage %d\n", acp
);
5027 csi
.fs
.fsCsb
[0] = 0;
5029 lf
.lfCharSet
= csi
.ciCharset
;
5032 want_vertical
= (lf
.lfFaceName
[0] == '@');
5034 /* Face families are in the top 4 bits of lfPitchAndFamily,
5035 so mask with 0xF0 before testing */
5037 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5038 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5039 strcpyW(lf
.lfFaceName
, defFixed
);
5040 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5041 strcpyW(lf
.lfFaceName
, defSerif
);
5042 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5043 strcpyW(lf
.lfFaceName
, defSans
);
5045 strcpyW(lf
.lfFaceName
, defSans
);
5046 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5047 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5048 font_link
= find_font_link(family
->FamilyName
);
5049 face_list
= get_face_list_from_family(family
);
5050 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5051 if (!(face
->scalable
|| can_use_bitmap
))
5053 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5055 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5061 last_resort_family
= NULL
;
5062 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5063 font_link
= find_font_link(family
->FamilyName
);
5064 face_list
= get_face_list_from_family(family
);
5065 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5066 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5067 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5068 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5071 if(can_use_bitmap
&& !last_resort_family
)
5072 last_resort_family
= family
;
5077 if(last_resort_family
) {
5078 family
= last_resort_family
;
5079 csi
.fs
.fsCsb
[0] = 0;
5083 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5084 face_list
= get_face_list_from_family(family
);
5085 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5086 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5087 csi
.fs
.fsCsb
[0] = 0;
5088 WARN("just using first face for now\n");
5091 if(can_use_bitmap
&& !last_resort_family
)
5092 last_resort_family
= family
;
5095 if(!last_resort_family
) {
5096 FIXME("can't find a single appropriate font - bailing\n");
5102 WARN("could only find a bitmap font - this will probably look awful!\n");
5103 family
= last_resort_family
;
5104 csi
.fs
.fsCsb
[0] = 0;
5107 it
= lf
.lfItalic
? 1 : 0;
5108 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5110 height
= lf
.lfHeight
;
5112 face
= best
= best_bitmap
= NULL
;
5113 font_link
= find_font_link(family
->FamilyName
);
5114 face_list
= get_face_list_from_family(family
);
5115 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5117 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5118 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5123 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5124 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5125 new_score
= (italic
^ it
) + (bold
^ bd
);
5126 if(!best
|| new_score
<= score
)
5128 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5129 italic
, bold
, it
, bd
);
5132 if(best
->scalable
&& score
== 0) break;
5136 newdiff
= height
- (signed int)(best
->size
.height
);
5138 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5139 if(!best_bitmap
|| new_score
< score
||
5140 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5142 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5145 if(score
== 0 && diff
== 0) break;
5152 face
= best
->scalable
? best
: best_bitmap
;
5153 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5154 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5157 height
= lf
.lfHeight
;
5161 if(csi
.fs
.fsCsb
[0]) {
5162 ret
->charset
= lf
.lfCharSet
;
5163 ret
->codepage
= csi
.ciACP
;
5166 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5168 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5169 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5171 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5173 if(!face
->scalable
) {
5174 /* Windows uses integer scaling factors for bitmap fonts */
5175 INT scale
, scaled_height
;
5176 GdiFont
*cachedfont
;
5178 /* FIXME: rotation of bitmap fonts is ignored */
5179 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5181 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5182 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5183 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5184 /* As we changed the matrix, we need to search the cache for the font again,
5185 * otherwise we might explode the cache. */
5186 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5187 TRACE("Found cached font after non-scalable matrix rescale!\n");
5192 calc_hash(&ret
->font_desc
);
5194 if (height
!= 0) height
= diff
;
5195 height
+= face
->size
.height
;
5197 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5198 scaled_height
= scale
* face
->size
.height
;
5199 /* Only jump to the next height if the difference <= 25% original height */
5200 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5201 /* The jump between unscaled and doubled is delayed by 1 */
5202 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5203 ret
->scale_y
= scale
;
5205 width
= face
->size
.x_ppem
>> 6;
5206 height
= face
->size
.y_ppem
>> 6;
5210 TRACE("font scale y: %f\n", ret
->scale_y
);
5212 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5221 ret
->ntmFlags
= face
->ntmFlags
;
5223 pick_charmap( ret
->ft_face
, ret
->charset
);
5225 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5226 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5227 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5228 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5229 create_child_font_list(ret
);
5231 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5233 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5234 if (length
!= GDI_ERROR
)
5236 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5237 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5238 TRACE("Loaded GSUB table of %i bytes\n",length
);
5239 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5240 if (!ret
->vert_feature
)
5242 TRACE("Vertical feature not found\n");
5243 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5244 ret
->GSUB_Table
= NULL
;
5248 ret
->aa_flags
= HIWORD( face
->flags
);
5250 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5256 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5258 switch (lf
.lfQuality
)
5260 case NONANTIALIASED_QUALITY
:
5261 case ANTIALIASED_QUALITY
:
5262 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5264 case CLEARTYPE_QUALITY
:
5265 case CLEARTYPE_NATURAL_QUALITY
:
5267 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5268 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5270 /* fixup the antialiasing flags for that font */
5273 case WINE_GGO_HRGB_BITMAP
:
5274 case WINE_GGO_HBGR_BITMAP
:
5275 case WINE_GGO_VRGB_BITMAP
:
5276 case WINE_GGO_VBGR_BITMAP
:
5277 if (is_subpixel_rendering_enabled()) break;
5278 *aa_flags
= GGO_GRAY4_BITMAP
;
5280 case GGO_GRAY2_BITMAP
:
5281 case GGO_GRAY4_BITMAP
:
5282 case GGO_GRAY8_BITMAP
:
5283 case WINE_GGO_GRAY16_BITMAP
:
5284 if (is_hinting_enabled())
5287 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5289 TRACE( "font %s %d aa disabled by GASP\n",
5290 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5291 *aa_flags
= GGO_BITMAP
;
5296 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5297 release_font( physdev
->font
);
5298 physdev
->font
= ret
;
5300 LeaveCriticalSection( &freetype_cs
);
5301 release_dc_ptr( dc
);
5302 return ret
? hfont
: 0;
5305 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5312 id
+= IDS_FIRST_SCRIPT
;
5313 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5314 if (!rsrc
) return 0;
5315 hMem
= LoadResource( gdi32_module
, rsrc
);
5316 if (!hMem
) return 0;
5318 p
= LockResource( hMem
);
5320 while (id
--) p
+= *p
+ 1;
5322 i
= min(LF_FACESIZE
- 1, *p
);
5323 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5329 /***************************************************
5330 * create_enum_charset_list
5332 * This function creates charset enumeration list because in DEFAULT_CHARSET
5333 * case, the ANSI codepage's charset takes precedence over other charsets.
5334 * This function works as a filter other than DEFAULT_CHARSET case.
5336 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5341 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5342 csi
.fs
.fsCsb
[0] != 0) {
5343 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5344 list
->element
[n
].charset
= csi
.ciCharset
;
5345 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5348 else { /* charset is DEFAULT_CHARSET or invalid. */
5352 /* Set the current codepage's charset as the first element. */
5354 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5355 csi
.fs
.fsCsb
[0] != 0) {
5356 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5357 list
->element
[n
].charset
= csi
.ciCharset
;
5358 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5359 mask
|= csi
.fs
.fsCsb
[0];
5363 /* Fill out left elements. */
5364 for (i
= 0; i
< 32; i
++) {
5366 fs
.fsCsb
[0] = 1L << i
;
5368 if (fs
.fsCsb
[0] & mask
)
5369 continue; /* skip, already added. */
5370 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5371 continue; /* skip, this is an invalid fsCsb bit. */
5373 list
->element
[n
].mask
= fs
.fsCsb
[0];
5374 list
->element
[n
].charset
= csi
.ciCharset
;
5375 load_script_name( i
, list
->element
[n
].name
);
5376 mask
|= fs
.fsCsb
[0];
5380 /* add catch all mask for remaining bits */
5383 list
->element
[n
].mask
= ~mask
;
5384 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5385 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5394 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5395 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5400 if (face
->cached_enum_data
)
5403 *pelf
= face
->cached_enum_data
->elf
;
5404 *pntm
= face
->cached_enum_data
->ntm
;
5405 *ptype
= face
->cached_enum_data
->type
;
5409 font
= alloc_font();
5411 if(face
->scalable
) {
5415 height
= face
->size
.y_ppem
>> 6;
5416 width
= face
->size
.x_ppem
>> 6;
5418 font
->scale_y
= 1.0;
5420 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5426 font
->name
= strdupW( family_name
);
5427 font
->ntmFlags
= face
->ntmFlags
;
5429 if (get_outline_text_metrics(font
))
5431 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5433 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5434 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5435 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5437 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5438 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5440 lstrcpynW(pelf
->elfFullName
,
5441 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5443 lstrcpynW(pelf
->elfStyle
,
5444 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5449 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5451 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5452 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5453 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5455 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5457 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5459 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5460 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5463 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5464 pntm
->ntmFontSig
= face
->fs
;
5466 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5468 pelf
->elfLogFont
.lfEscapement
= 0;
5469 pelf
->elfLogFont
.lfOrientation
= 0;
5470 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5471 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5472 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5473 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5474 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5475 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5476 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5477 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5478 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5479 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5480 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5483 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5484 *ptype
|= TRUETYPE_FONTTYPE
;
5485 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5486 *ptype
|= DEVICE_FONTTYPE
;
5487 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5488 *ptype
|= RASTER_FONTTYPE
;
5490 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5491 if (face
->cached_enum_data
)
5493 face
->cached_enum_data
->elf
= *pelf
;
5494 face
->cached_enum_data
->ntm
= *pntm
;
5495 face
->cached_enum_data
->type
= *ptype
;
5501 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5504 const struct list
*face_list
;
5506 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5508 face_list
= get_face_list_from_family(family
);
5509 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5510 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5515 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5517 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5519 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5522 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5523 FONTENUMPROCW proc
, LPARAM lparam
)
5526 NEWTEXTMETRICEXW ntm
;
5530 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5531 for(i
= 0; i
< list
->total
; i
++) {
5532 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5533 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5534 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5535 i
= list
->total
; /* break out of loop after enumeration */
5539 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5540 /* use the DEFAULT_CHARSET case only if no other charset is present */
5541 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5542 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5543 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5544 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5545 if (!elf
.elfScript
[0])
5546 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5548 /* Font Replacement */
5549 if (family
!= face
->family
)
5551 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5553 strcpyW(elf
.elfFullName
, face
->FullName
);
5555 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5557 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5558 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5559 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5560 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5561 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5562 ntm
.ntmTm
.ntmFlags
);
5563 /* release section before callback (FIXME) */
5564 LeaveCriticalSection( &freetype_cs
);
5565 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5566 EnterCriticalSection( &freetype_cs
);
5571 /*************************************************************
5572 * freetype_EnumFonts
5574 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5578 const struct list
*face_list
;
5580 struct enum_charset_list enum_charsets
;
5584 lf
.lfCharSet
= DEFAULT_CHARSET
;
5585 lf
.lfPitchAndFamily
= 0;
5586 lf
.lfFaceName
[0] = 0;
5590 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5592 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5595 EnterCriticalSection( &freetype_cs
);
5596 if(plf
->lfFaceName
[0]) {
5598 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5601 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5602 debugstr_w(psub
->to
.name
));
5604 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5608 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5609 if (!family_matches(family
, plf
)) continue;
5610 face_list
= get_face_list_from_family(family
);
5611 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5612 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5613 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5617 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5618 face_list
= get_face_list_from_family(family
);
5619 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5620 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5623 LeaveCriticalSection( &freetype_cs
);
5627 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5629 pt
->x
.value
= vec
->x
>> 6;
5630 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5631 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5632 pt
->y
.value
= vec
->y
>> 6;
5633 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5634 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5638 /***************************************************
5639 * According to the MSDN documentation on WideCharToMultiByte,
5640 * certain codepages cannot set the default_used parameter.
5641 * This returns TRUE if the codepage can set that parameter, false else
5642 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5644 static BOOL
codepage_sets_default_used(UINT codepage
)
5658 * GSUB Table handling functions
5661 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5663 const GSUB_CoverageFormat1
* cf1
;
5667 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5669 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5671 TRACE("Coverage Format 1, %i glyphs\n",count
);
5672 for (i
= 0; i
< count
; i
++)
5673 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5677 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5679 const GSUB_CoverageFormat2
* cf2
;
5682 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5684 count
= GET_BE_WORD(cf2
->RangeCount
);
5685 TRACE("Coverage Format 2, %i ranges\n",count
);
5686 for (i
= 0; i
< count
; i
++)
5688 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5690 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5691 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5693 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5694 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5700 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5705 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5709 const GSUB_LookupList
*lookup
;
5710 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5712 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5713 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5715 const GSUB_LookupTable
*look
;
5716 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5717 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5718 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5719 if (GET_BE_WORD(look
->LookupType
) != 1)
5720 FIXME("We only handle SubType 1\n");
5725 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5727 const GSUB_SingleSubstFormat1
*ssf1
;
5728 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5729 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5730 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5732 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5733 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5734 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5736 TRACE(" Glyph 0x%x ->",glyph
);
5737 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5738 TRACE(" 0x%x\n",glyph
);
5743 const GSUB_SingleSubstFormat2
*ssf2
;
5747 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5748 offset
= GET_BE_WORD(ssf1
->Coverage
);
5749 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5750 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5751 TRACE(" Coverage index %i\n",index
);
5754 TRACE(" Glyph is 0x%x ->",glyph
);
5755 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5756 TRACE("0x%x\n",glyph
);
5766 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5768 const GSUB_Header
*header
;
5769 const GSUB_Feature
*feature
;
5771 if (!font
->GSUB_Table
)
5774 header
= font
->GSUB_Table
;
5775 feature
= font
->vert_feature
;
5777 return GSUB_apply_feature(header
, feature
, glyph
);
5780 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5784 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5785 WCHAR wc
= (WCHAR
)glyph
;
5787 BOOL
*default_used_pointer
;
5790 default_used_pointer
= NULL
;
5791 default_used
= FALSE
;
5792 if (codepage_sets_default_used(font
->codepage
))
5793 default_used_pointer
= &default_used
;
5794 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5796 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
5797 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
5802 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5803 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5807 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5809 if (glyph
< 0x100) glyph
+= 0xf000;
5810 /* there is a number of old pre-Unicode "broken" TTFs, which
5811 do have symbols at U+00XX instead of U+f0XX */
5812 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5813 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5815 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5820 static FT_UInt
get_default_char_index(GdiFont
*font
)
5822 FT_UInt default_char
;
5824 if (FT_IS_SFNT(font
->ft_face
))
5826 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
5827 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
5832 get_text_metrics(font
, &textm
);
5833 default_char
= textm
.tmDefaultChar
;
5836 return default_char
;
5839 /*************************************************************
5840 * freetype_GetGlyphIndices
5842 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5844 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5847 BOOL got_default
= FALSE
;
5851 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5852 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5855 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5857 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5862 EnterCriticalSection( &freetype_cs
);
5864 for(i
= 0; i
< count
; i
++)
5866 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5871 default_char
= get_default_char_index(physdev
->font
);
5874 pgi
[i
] = default_char
;
5877 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
5879 LeaveCriticalSection( &freetype_cs
);
5883 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5885 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5886 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5889 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5891 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5892 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5895 static inline BYTE
get_max_level( UINT format
)
5899 case GGO_GRAY2_BITMAP
: return 4;
5900 case GGO_GRAY4_BITMAP
: return 16;
5901 case GGO_GRAY8_BITMAP
: return 64;
5906 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5908 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5909 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
5912 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5913 FT_Face ft_face
= incoming_font
->ft_face
;
5914 GdiFont
*font
= incoming_font
;
5915 FT_Glyph_Metrics metrics
;
5916 FT_UInt glyph_index
;
5917 DWORD width
, height
, pitch
, needed
= 0;
5918 FT_Bitmap ft_bitmap
;
5920 INT left
, right
, top
= 0, bottom
= 0, adv
;
5922 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5923 double widthRatio
= 1.0;
5924 FT_Matrix transMat
= identityMat
;
5925 FT_Matrix transMatUnrotated
;
5926 FT_Matrix transMatTategaki
;
5927 BOOL needsTransform
= FALSE
;
5928 BOOL tategaki
= (font
->name
[0] == '@');
5929 UINT original_index
;
5930 LONG avgAdvance
= 0;
5933 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5934 buflen
, buf
, lpmat
);
5936 TRACE("font transform %f %f %f %f\n",
5937 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5938 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5940 if(format
& GGO_GLYPH_INDEX
) {
5941 glyph_index
= glyph
;
5942 original_index
= glyph
;
5943 format
&= ~GGO_GLYPH_INDEX
;
5945 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5946 ft_face
= font
->ft_face
;
5947 original_index
= glyph_index
;
5950 if(format
& GGO_UNHINTED
) {
5951 load_flags
|= FT_LOAD_NO_HINTING
;
5952 format
&= ~GGO_UNHINTED
;
5955 /* tategaki never appears to happen to lower glyph index */
5956 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5959 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5960 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5961 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5962 font
->gmsize
* sizeof(GM
*));
5964 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5965 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5967 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5968 *abc
= FONT_GM(font
,original_index
)->abc
;
5969 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5970 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5971 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5972 return 1; /* FIXME */
5976 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5977 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5979 /* Scaling factor */
5984 get_text_metrics(font
, &tm
);
5986 widthRatio
= (double)font
->aveWidth
;
5987 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5990 widthRatio
= font
->scale_y
;
5992 /* Scaling transform */
5993 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5996 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5999 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6001 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6002 needsTransform
= TRUE
;
6005 /* Slant transform */
6006 if (font
->fake_italic
) {
6009 slantMat
.xx
= (1 << 16);
6010 slantMat
.xy
= ((1 << 16) >> 2);
6012 slantMat
.yy
= (1 << 16);
6013 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6014 needsTransform
= TRUE
;
6017 /* Rotation transform */
6018 transMatUnrotated
= transMat
;
6019 transMatTategaki
= transMat
;
6020 if(font
->orientation
|| tategaki
) {
6021 FT_Matrix rotationMat
;
6022 FT_Matrix taterotationMat
;
6025 double orient
= font
->orientation
/ 10.0;
6026 double tate_orient
= 0.f
;
6029 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6031 tate_orient
= font
->orientation
/10.0;
6035 angle
= FT_FixedFromFloat(orient
);
6036 pFT_Vector_Unit(&vecAngle
, angle
);
6037 rotationMat
.xx
= vecAngle
.x
;
6038 rotationMat
.xy
= -vecAngle
.y
;
6039 rotationMat
.yx
= -rotationMat
.xy
;
6040 rotationMat
.yy
= rotationMat
.xx
;
6042 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6047 angle
= FT_FixedFromFloat(tate_orient
);
6048 pFT_Vector_Unit(&vecAngle
, angle
);
6049 taterotationMat
.xx
= vecAngle
.x
;
6050 taterotationMat
.xy
= -vecAngle
.y
;
6051 taterotationMat
.yx
= -taterotationMat
.xy
;
6052 taterotationMat
.yy
= taterotationMat
.xx
;
6053 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6056 needsTransform
= TRUE
;
6059 /* World transform */
6060 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6063 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6064 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6065 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6066 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6067 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6068 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6069 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6070 needsTransform
= TRUE
;
6073 /* Extra transformation specified by caller */
6074 if (!is_identity_MAT2(lpmat
))
6077 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6078 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6079 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6080 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6081 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6082 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6083 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6084 needsTransform
= TRUE
;
6087 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6089 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6092 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6096 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6097 * by the text metrics. The proper behavior is to clip the glyph metrics to
6098 * fit within the maximums specified in the text metrics. */
6099 metrics
= ft_face
->glyph
->metrics
;
6100 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6101 get_bitmap_text_metrics(incoming_font
)) {
6102 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6103 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6104 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6105 metrics
.horiBearingY
= top
;
6106 metrics
.height
= top
- bottom
;
6108 /* TODO: Are we supposed to clip the width as well...? */
6109 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6112 if(FT_IS_SCALABLE(incoming_font
->ft_face
)) {
6114 if (get_text_metrics(incoming_font
, &tm
) &&
6115 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6116 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6117 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6119 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6120 TRACE("Fixed-pitch full-width character detected\n");
6122 avgAdvance
= 0; /* cancel this feature */
6126 if(!needsTransform
) {
6127 left
= (INT
)(metrics
.horiBearingX
) & -64;
6128 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6130 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6132 adv
= (INT
)avgAdvance
* 2;
6134 top
= (metrics
.horiBearingY
+ 63) & -64;
6135 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6136 lpgm
->gmCellIncX
= adv
;
6137 lpgm
->gmCellIncY
= 0;
6144 for(xc
= 0; xc
< 2; xc
++) {
6145 for(yc
= 0; yc
< 2; yc
++) {
6146 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6147 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6148 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6149 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6150 if(xc
== 0 && yc
== 0) {
6151 left
= right
= vec
.x
;
6152 top
= bottom
= vec
.y
;
6154 if(vec
.x
< left
) left
= vec
.x
;
6155 else if(vec
.x
> right
) right
= vec
.x
;
6156 if(vec
.y
< bottom
) bottom
= vec
.y
;
6157 else if(vec
.y
> top
) top
= vec
.y
;
6162 right
= (right
+ 63) & -64;
6163 bottom
= bottom
& -64;
6164 top
= (top
+ 63) & -64;
6166 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6167 vec
.x
= metrics
.horiAdvance
;
6169 pFT_Vector_Transform(&vec
, &transMat
);
6170 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6171 if (!avgAdvance
|| vec
.y
)
6172 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6174 vec
.x
= incoming_font
->ntmAvgWidth
;
6176 pFT_Vector_Transform(&vec
, &transMat
);
6177 lpgm
->gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6180 vec
.x
= metrics
.horiAdvance
;
6182 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6183 if (!avgAdvance
|| vec
.y
)
6184 adv
= (vec
.x
+63) >> 6;
6186 vec
.x
= incoming_font
->ntmAvgWidth
;
6188 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6189 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6193 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6194 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6195 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
6196 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
6197 abc
->abcA
= left
>> 6;
6198 abc
->abcB
= (right
- left
) >> 6;
6199 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6201 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6202 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6203 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6205 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6206 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6208 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6209 FONT_GM(font
,original_index
)->abc
= *abc
;
6210 FONT_GM(font
,original_index
)->init
= TRUE
;
6213 if(format
== GGO_METRICS
)
6215 return 1; /* FIXME */
6218 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6219 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6221 TRACE("loaded a bitmap\n");
6227 width
= lpgm
->gmBlackBoxX
;
6228 height
= lpgm
->gmBlackBoxY
;
6229 pitch
= ((width
+ 31) >> 5) << 2;
6230 needed
= pitch
* height
;
6232 if(!buf
|| !buflen
) break;
6234 switch(ft_face
->glyph
->format
) {
6235 case ft_glyph_format_bitmap
:
6237 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6238 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6239 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6241 memcpy(dst
, src
, w
);
6242 src
+= ft_face
->glyph
->bitmap
.pitch
;
6248 case ft_glyph_format_outline
:
6249 ft_bitmap
.width
= width
;
6250 ft_bitmap
.rows
= height
;
6251 ft_bitmap
.pitch
= pitch
;
6252 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6253 ft_bitmap
.buffer
= buf
;
6256 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6258 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6260 /* Note: FreeType will only set 'black' bits for us. */
6261 memset(buf
, 0, needed
);
6262 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6266 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6271 case GGO_GRAY2_BITMAP
:
6272 case GGO_GRAY4_BITMAP
:
6273 case GGO_GRAY8_BITMAP
:
6274 case WINE_GGO_GRAY16_BITMAP
:
6276 unsigned int max_level
, row
, col
;
6279 width
= lpgm
->gmBlackBoxX
;
6280 height
= lpgm
->gmBlackBoxY
;
6281 pitch
= (width
+ 3) / 4 * 4;
6282 needed
= pitch
* height
;
6284 if(!buf
|| !buflen
) break;
6286 max_level
= get_max_level( format
);
6288 switch(ft_face
->glyph
->format
) {
6289 case ft_glyph_format_bitmap
:
6291 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6292 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6294 memset( buf
, 0, needed
);
6296 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6297 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6298 src
+= ft_face
->glyph
->bitmap
.pitch
;
6303 case ft_glyph_format_outline
:
6305 ft_bitmap
.width
= width
;
6306 ft_bitmap
.rows
= height
;
6307 ft_bitmap
.pitch
= pitch
;
6308 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6309 ft_bitmap
.buffer
= buf
;
6312 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6314 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6316 memset(ft_bitmap
.buffer
, 0, buflen
);
6318 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6320 if (max_level
!= 255)
6322 for (row
= 0, start
= buf
; row
< height
; row
++)
6324 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6325 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6333 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6339 case WINE_GGO_HRGB_BITMAP
:
6340 case WINE_GGO_HBGR_BITMAP
:
6341 case WINE_GGO_VRGB_BITMAP
:
6342 case WINE_GGO_VBGR_BITMAP
:
6343 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6345 switch (ft_face
->glyph
->format
)
6347 case FT_GLYPH_FORMAT_BITMAP
:
6352 width
= lpgm
->gmBlackBoxX
;
6353 height
= lpgm
->gmBlackBoxY
;
6355 needed
= pitch
* height
;
6357 if (!buf
|| !buflen
) break;
6359 memset(buf
, 0, buflen
);
6361 src
= ft_face
->glyph
->bitmap
.buffer
;
6362 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6364 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6367 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6369 if ( src
[x
/ 8] & masks
[x
% 8] )
6370 ((unsigned int *)dst
)[x
] = ~0u;
6379 case FT_GLYPH_FORMAT_OUTLINE
:
6383 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6384 INT x_shift
, y_shift
;
6386 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6387 FT_Render_Mode render_mode
=
6388 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6389 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6391 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6393 if ( render_mode
== FT_RENDER_MODE_LCD
)
6395 lpgm
->gmBlackBoxX
+= 2;
6396 lpgm
->gmptGlyphOrigin
.x
-= 1;
6400 lpgm
->gmBlackBoxY
+= 2;
6401 lpgm
->gmptGlyphOrigin
.y
+= 1;
6405 width
= lpgm
->gmBlackBoxX
;
6406 height
= lpgm
->gmBlackBoxY
;
6408 needed
= pitch
* height
;
6410 if (!buf
|| !buflen
) break;
6412 memset(buf
, 0, buflen
);
6414 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6416 if ( needsTransform
)
6417 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
6419 if ( pFT_Library_SetLcdFilter
)
6420 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6421 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6423 src
= ft_face
->glyph
->bitmap
.buffer
;
6424 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6425 src_width
= ft_face
->glyph
->bitmap
.width
;
6426 src_height
= ft_face
->glyph
->bitmap
.rows
;
6428 if ( render_mode
== FT_RENDER_MODE_LCD
)
6436 rgb_interval
= src_pitch
;
6441 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6444 src
+= hmul
* -x_shift
;
6445 src_width
-= hmul
* -x_shift
;
6447 else if ( x_shift
> 0 )
6453 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6456 src
+= src_pitch
* vmul
* -y_shift
;
6457 src_height
-= vmul
* -y_shift
;
6459 else if ( y_shift
> 0 )
6461 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
6465 width
= min( width
, src_width
/ hmul
);
6466 height
= min( height
, src_height
/ vmul
);
6470 for ( x
= 0; x
< width
; x
++ )
6474 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6475 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6476 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6477 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6481 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6482 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6483 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6484 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6487 src
+= src_pitch
* vmul
;
6488 dst
+= pitch
/ sizeof(*dst
);
6495 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6507 int contour
, point
= 0, first_pt
;
6508 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6509 TTPOLYGONHEADER
*pph
;
6511 DWORD pph_start
, cpfx
, type
;
6513 if(buflen
== 0) buf
= NULL
;
6515 if (needsTransform
&& buf
) {
6516 pFT_Outline_Transform(outline
, &transMatTategaki
);
6519 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6520 /* Ignore contours containing one point */
6521 if(point
== outline
->contours
[contour
]) {
6527 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6530 pph
->dwType
= TT_POLYGON_TYPE
;
6531 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6533 needed
+= sizeof(*pph
);
6535 while(point
<= outline
->contours
[contour
]) {
6536 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6537 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6538 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6542 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6545 } while(point
<= outline
->contours
[contour
] &&
6546 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6547 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6548 /* At the end of a contour Windows adds the start point, but
6550 if(point
> outline
->contours
[contour
] &&
6551 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6553 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6555 } else if(point
<= outline
->contours
[contour
] &&
6556 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6557 /* add closing pt for bezier */
6559 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6567 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6570 pph
->cb
= needed
- pph_start
;
6576 /* Convert the quadratic Beziers to cubic Beziers.
6577 The parametric eqn for a cubic Bezier is, from PLRM:
6578 r(t) = at^3 + bt^2 + ct + r0
6579 with the control points:
6584 A quadratic Bezier has the form:
6585 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6587 So equating powers of t leads to:
6588 r1 = 2/3 p1 + 1/3 p0
6589 r2 = 2/3 p1 + 1/3 p2
6590 and of course r0 = p0, r3 = p2
6593 int contour
, point
= 0, first_pt
;
6594 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6595 TTPOLYGONHEADER
*pph
;
6597 DWORD pph_start
, cpfx
, type
;
6598 FT_Vector cubic_control
[4];
6599 if(buflen
== 0) buf
= NULL
;
6601 if (needsTransform
&& buf
) {
6602 pFT_Outline_Transform(outline
, &transMat
);
6605 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6607 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6610 pph
->dwType
= TT_POLYGON_TYPE
;
6611 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6613 needed
+= sizeof(*pph
);
6615 while(point
<= outline
->contours
[contour
]) {
6616 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6617 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6618 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6621 if(type
== TT_PRIM_LINE
) {
6623 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6627 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6630 /* FIXME: Possible optimization in endpoint calculation
6631 if there are two consecutive curves */
6632 cubic_control
[0] = outline
->points
[point
-1];
6633 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6634 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6635 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6636 cubic_control
[0].x
>>= 1;
6637 cubic_control
[0].y
>>= 1;
6639 if(point
+1 > outline
->contours
[contour
])
6640 cubic_control
[3] = outline
->points
[first_pt
];
6642 cubic_control
[3] = outline
->points
[point
+1];
6643 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6644 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6645 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6646 cubic_control
[3].x
>>= 1;
6647 cubic_control
[3].y
>>= 1;
6650 /* r1 = 1/3 p0 + 2/3 p1
6651 r2 = 1/3 p2 + 2/3 p1 */
6652 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6653 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6654 cubic_control
[2] = cubic_control
[1];
6655 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6656 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6657 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6658 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6660 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6661 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6662 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6667 } while(point
<= outline
->contours
[contour
] &&
6668 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6669 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6670 /* At the end of a contour Windows adds the start point,
6671 but only for Beziers and we've already done that.
6673 if(point
<= outline
->contours
[contour
] &&
6674 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6675 /* This is the closing pt of a bezier, but we've already
6676 added it, so just inc point and carry on */
6683 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6686 pph
->cb
= needed
- pph_start
;
6692 FIXME("Unsupported format %d\n", format
);
6698 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6700 FT_Face ft_face
= font
->ft_face
;
6701 FT_WinFNT_HeaderRec winfnt_header
;
6702 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6703 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6704 font
->potm
->otmSize
= size
;
6706 #define TM font->potm->otmTextMetrics
6707 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6709 TM
.tmHeight
= winfnt_header
.pixel_height
;
6710 TM
.tmAscent
= winfnt_header
.ascent
;
6711 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6712 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6713 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6714 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6715 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6716 TM
.tmWeight
= winfnt_header
.weight
;
6718 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6719 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6720 TM
.tmFirstChar
= winfnt_header
.first_char
;
6721 TM
.tmLastChar
= winfnt_header
.last_char
;
6722 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6723 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6724 TM
.tmItalic
= winfnt_header
.italic
;
6725 TM
.tmUnderlined
= font
->underline
;
6726 TM
.tmStruckOut
= font
->strikeout
;
6727 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6728 TM
.tmCharSet
= winfnt_header
.charset
;
6732 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6733 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6734 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6735 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6736 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6737 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6738 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6739 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6741 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6742 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6744 TM
.tmLastChar
= 255;
6745 TM
.tmDefaultChar
= 32;
6746 TM
.tmBreakChar
= 32;
6747 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6748 TM
.tmUnderlined
= font
->underline
;
6749 TM
.tmStruckOut
= font
->strikeout
;
6750 /* NB inverted meaning of TMPF_FIXED_PITCH */
6751 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6752 TM
.tmCharSet
= font
->charset
;
6760 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6762 double scale_x
, scale_y
;
6766 scale_x
= (double)font
->aveWidth
;
6767 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6770 scale_x
= font
->scale_y
;
6772 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6773 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6775 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6776 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6778 SCALE_Y(ptm
->tmHeight
);
6779 SCALE_Y(ptm
->tmAscent
);
6780 SCALE_Y(ptm
->tmDescent
);
6781 SCALE_Y(ptm
->tmInternalLeading
);
6782 SCALE_Y(ptm
->tmExternalLeading
);
6783 SCALE_Y(ptm
->tmOverhang
);
6785 SCALE_X(ptm
->tmAveCharWidth
);
6786 SCALE_X(ptm
->tmMaxCharWidth
);
6792 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6794 double scale_x
, scale_y
;
6798 scale_x
= (double)font
->aveWidth
;
6799 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6802 scale_x
= font
->scale_y
;
6804 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6805 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6807 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6809 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6810 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6812 SCALE_Y(potm
->otmAscent
);
6813 SCALE_Y(potm
->otmDescent
);
6814 SCALE_Y(potm
->otmLineGap
);
6815 SCALE_Y(potm
->otmsCapEmHeight
);
6816 SCALE_Y(potm
->otmsXHeight
);
6817 SCALE_Y(potm
->otmrcFontBox
.top
);
6818 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6819 SCALE_X(potm
->otmrcFontBox
.left
);
6820 SCALE_X(potm
->otmrcFontBox
.right
);
6821 SCALE_Y(potm
->otmMacAscent
);
6822 SCALE_Y(potm
->otmMacDescent
);
6823 SCALE_Y(potm
->otmMacLineGap
);
6824 SCALE_X(potm
->otmptSubscriptSize
.x
);
6825 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6826 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6827 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6828 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6829 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6830 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6831 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6832 SCALE_Y(potm
->otmsStrikeoutSize
);
6833 SCALE_Y(potm
->otmsStrikeoutPosition
);
6834 SCALE_Y(potm
->otmsUnderscoreSize
);
6835 SCALE_Y(potm
->otmsUnderscorePosition
);
6841 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6845 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6847 /* Make sure that the font has sane width/height ratio */
6850 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6852 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6857 *ptm
= font
->potm
->otmTextMetrics
;
6858 scale_font_metrics(font
, ptm
);
6862 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6866 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6868 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6874 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6877 FT_Face ft_face
= font
->ft_face
;
6878 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
6880 TT_HoriHeader
*pHori
;
6881 TT_Postscript
*pPost
;
6883 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
6885 INT ascent
, descent
;
6887 TRACE("font=%p\n", font
);
6889 if(!FT_IS_SCALABLE(ft_face
))
6892 needed
= sizeof(*font
->potm
);
6894 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6895 family_nameW
= strdupW(font
->name
);
6897 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
6899 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6902 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6903 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
6905 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
6907 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
6909 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6912 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6913 face_nameW
= strdupW(font
->name
);
6915 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
6916 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
6918 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
6920 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6923 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
6924 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6925 full_nameW
= strdupW(fake_nameW
);
6927 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
6929 /* These names should be read from the TT name table */
6931 /* length of otmpFamilyName */
6934 /* length of otmpFaceName */
6937 /* length of otmpStyleName */
6940 /* length of otmpFullName */
6944 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
6946 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6948 FIXME("Can't find OS/2 table - not TT font?\n");
6952 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6954 FIXME("Can't find HHEA table - not TT font?\n");
6958 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6960 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",
6961 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6962 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6963 pOS2
->xAvgCharWidth
,
6964 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6965 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6966 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6968 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6969 font
->potm
->otmSize
= needed
;
6971 #define TM font->potm->otmTextMetrics
6973 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6974 ascent
= pHori
->Ascender
;
6975 descent
= -pHori
->Descender
;
6977 ascent
= pOS2
->usWinAscent
;
6978 descent
= pOS2
->usWinDescent
;
6981 font
->ntmCellHeight
= ascent
+ descent
;
6982 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6984 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6985 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6988 TM
.tmAscent
= font
->yMax
;
6989 TM
.tmDescent
= -font
->yMin
;
6990 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6992 TM
.tmAscent
= SCALE_Y(ascent
);
6993 TM
.tmDescent
= SCALE_Y(descent
);
6994 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
6997 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7000 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7002 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7003 ((ascent
+ descent
) -
7004 (pHori
->Ascender
- pHori
->Descender
))));
7006 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7007 if (TM
.tmAveCharWidth
== 0) {
7008 TM
.tmAveCharWidth
= 1;
7010 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7011 TM
.tmWeight
= FW_REGULAR
;
7012 if (font
->fake_bold
)
7013 TM
.tmWeight
= FW_BOLD
;
7016 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7018 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7019 TM
.tmWeight
= pOS2
->usWeightClass
;
7021 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7022 TM
.tmWeight
= pOS2
->usWeightClass
;
7025 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7026 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7027 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7028 * symbol range to 0 - f0ff
7031 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7036 case 1257: /* Baltic */
7037 TM
.tmLastChar
= 0xf8fd;
7040 TM
.tmLastChar
= 0xf0ff;
7042 TM
.tmBreakChar
= 0x20;
7043 TM
.tmDefaultChar
= 0x1f;
7047 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7048 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7050 if(pOS2
->usFirstCharIndex
<= 1)
7051 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7052 else if (pOS2
->usFirstCharIndex
> 0xff)
7053 TM
.tmBreakChar
= 0x20;
7055 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7056 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7058 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7059 TM
.tmUnderlined
= font
->underline
;
7060 TM
.tmStruckOut
= font
->strikeout
;
7062 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7063 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7064 (pOS2
->version
== 0xFFFFU
||
7065 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7066 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7068 TM
.tmPitchAndFamily
= 0;
7070 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7072 case PAN_FAMILY_SCRIPT
:
7073 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7076 case PAN_FAMILY_DECORATIVE
:
7077 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7082 case PAN_FAMILY_TEXT_DISPLAY
:
7083 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7084 /* which is clearly not what the panose spec says. */
7086 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7087 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7088 TM
.tmPitchAndFamily
= FF_MODERN
;
7091 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7096 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7099 case PAN_SERIF_COVE
:
7100 case PAN_SERIF_OBTUSE_COVE
:
7101 case PAN_SERIF_SQUARE_COVE
:
7102 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7103 case PAN_SERIF_SQUARE
:
7104 case PAN_SERIF_THIN
:
7105 case PAN_SERIF_BONE
:
7106 case PAN_SERIF_EXAGGERATED
:
7107 case PAN_SERIF_TRIANGLE
:
7108 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7111 case PAN_SERIF_NORMAL_SANS
:
7112 case PAN_SERIF_OBTUSE_SANS
:
7113 case PAN_SERIF_PERP_SANS
:
7114 case PAN_SERIF_FLARED
:
7115 case PAN_SERIF_ROUNDED
:
7116 TM
.tmPitchAndFamily
|= FF_SWISS
;
7123 if(FT_IS_SCALABLE(ft_face
))
7124 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7126 if(FT_IS_SFNT(ft_face
))
7128 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7129 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7131 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7134 TM
.tmCharSet
= font
->charset
;
7136 font
->potm
->otmFiller
= 0;
7137 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7138 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7139 font
->potm
->otmfsType
= pOS2
->fsType
;
7140 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7141 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7142 font
->potm
->otmItalicAngle
= 0; /* POST table */
7143 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7144 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7145 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7146 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7147 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7148 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7149 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7150 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7151 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7152 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7153 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7154 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7155 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7156 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7157 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7158 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7159 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7160 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7161 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7162 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7163 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7164 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7165 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7166 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7168 font
->potm
->otmsUnderscoreSize
= 0;
7169 font
->potm
->otmsUnderscorePosition
= 0;
7171 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7172 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7178 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7179 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7180 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7181 strcpyW((WCHAR
*)cp
, family_nameW
);
7183 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7184 strcpyW((WCHAR
*)cp
, style_nameW
);
7186 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7187 strcpyW((WCHAR
*)cp
, face_nameW
);
7189 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7190 strcpyW((WCHAR
*)cp
, full_nameW
);
7194 HeapFree(GetProcessHeap(), 0, style_nameW
);
7195 HeapFree(GetProcessHeap(), 0, family_nameW
);
7196 HeapFree(GetProcessHeap(), 0, face_nameW
);
7197 HeapFree(GetProcessHeap(), 0, full_nameW
);
7201 /*************************************************************
7202 * freetype_GetGlyphOutline
7204 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7205 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7207 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7213 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7214 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7218 EnterCriticalSection( &freetype_cs
);
7219 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7220 LeaveCriticalSection( &freetype_cs
);
7224 /*************************************************************
7225 * freetype_GetTextMetrics
7227 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7229 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7234 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7235 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7239 EnterCriticalSection( &freetype_cs
);
7240 ret
= get_text_metrics( physdev
->font
, metrics
);
7241 LeaveCriticalSection( &freetype_cs
);
7245 /*************************************************************
7246 * freetype_GetOutlineTextMetrics
7248 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7250 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7255 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7256 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7259 TRACE("font=%p\n", physdev
->font
);
7261 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7264 EnterCriticalSection( &freetype_cs
);
7266 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7268 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7270 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7271 scale_outline_font_metrics(physdev
->font
, potm
);
7273 ret
= physdev
->font
->potm
->otmSize
;
7275 LeaveCriticalSection( &freetype_cs
);
7279 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7281 child
->font
= alloc_font();
7282 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7283 if(!child
->font
->ft_face
)
7285 free_font(child
->font
);
7290 child
->font
->font_desc
= font
->font_desc
;
7291 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7292 child
->font
->orientation
= font
->orientation
;
7293 child
->font
->scale_y
= font
->scale_y
;
7294 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7295 child
->font
->base_font
= font
;
7296 TRACE("created child font %p for base %p\n", child
->font
, font
);
7300 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
7303 CHILD_FONT
*child_font
;
7306 font
= font
->base_font
;
7308 *linked_font
= font
;
7310 if((*glyph
= get_glyph_index(font
, c
)))
7312 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7316 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7318 if(!child_font
->font
)
7319 if(!load_child_font(font
, child_font
))
7322 if(!child_font
->font
->ft_face
)
7324 g
= get_glyph_index(child_font
->font
, c
);
7325 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7329 *linked_font
= child_font
->font
;
7333 *glyph
= get_default_char_index(font
);
7337 /*************************************************************
7338 * freetype_GetCharWidth
7340 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7342 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7346 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7350 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7351 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7354 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7357 EnterCriticalSection( &freetype_cs
);
7358 for(c
= firstChar
; c
<= lastChar
; c
++) {
7359 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7360 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7362 LeaveCriticalSection( &freetype_cs
);
7366 /*************************************************************
7367 * freetype_GetCharABCWidths
7369 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7371 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7374 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7378 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7379 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7382 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7385 EnterCriticalSection( &freetype_cs
);
7387 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7388 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7390 LeaveCriticalSection( &freetype_cs
);
7394 /*************************************************************
7395 * freetype_GetCharABCWidthsI
7397 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7399 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7402 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7406 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7407 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7410 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7414 EnterCriticalSection( &freetype_cs
);
7416 for(c
= 0; c
< count
; c
++, buffer
++)
7417 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7418 &gm
, buffer
, 0, NULL
, &identity
);
7420 LeaveCriticalSection( &freetype_cs
);
7424 /*************************************************************
7425 * freetype_GetTextExtentExPoint
7427 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7429 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7433 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7437 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7438 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7441 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7444 EnterCriticalSection( &freetype_cs
);
7446 for (idx
= pos
= 0; idx
< count
; idx
++)
7448 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7449 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7453 LeaveCriticalSection( &freetype_cs
);
7457 /*************************************************************
7458 * freetype_GetTextExtentExPointI
7460 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7462 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7466 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7470 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7471 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7474 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7477 EnterCriticalSection( &freetype_cs
);
7479 for (idx
= pos
= 0; idx
< count
; idx
++)
7481 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7482 &gm
, &abc
, 0, NULL
, &identity
);
7483 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7487 LeaveCriticalSection( &freetype_cs
);
7491 /*************************************************************
7492 * freetype_GetFontData
7494 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7496 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7500 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7501 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7504 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7505 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7506 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7508 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7511 /*************************************************************
7512 * freetype_GetTextFace
7514 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7517 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7521 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7522 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7525 n
= strlenW(physdev
->font
->name
) + 1;
7528 lstrcpynW(str
, physdev
->font
->name
, count
);
7534 /*************************************************************
7535 * freetype_GetTextCharsetInfo
7537 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7539 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7543 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7544 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7546 if (fs
) *fs
= physdev
->font
->fs
;
7547 return physdev
->font
->charset
;
7550 /* Retrieve a list of supported Unicode ranges for a given font.
7551 * Can be called with NULL gs to calculate the buffer size. Returns
7552 * the number of ranges found.
7554 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7556 DWORD num_ranges
= 0;
7558 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7561 FT_ULong char_code
, char_code_prev
;
7564 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7566 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7567 face
->num_glyphs
, glyph_code
, char_code
);
7569 if (!glyph_code
) return 0;
7573 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7574 gs
->ranges
[0].cGlyphs
= 0;
7575 gs
->cGlyphsSupported
= 0;
7581 if (char_code
< char_code_prev
)
7583 ERR("expected increasing char code from FT_Get_Next_Char\n");
7586 if (char_code
- char_code_prev
> 1)
7591 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7592 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7593 gs
->cGlyphsSupported
++;
7598 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7599 gs
->cGlyphsSupported
++;
7601 char_code_prev
= char_code
;
7602 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7606 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7611 /*************************************************************
7612 * freetype_GetFontUnicodeRanges
7614 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7616 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7617 DWORD size
, num_ranges
;
7621 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7622 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7625 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7626 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7629 glyphset
->cbThis
= size
;
7630 glyphset
->cRanges
= num_ranges
;
7631 glyphset
->flAccel
= 0;
7636 /*************************************************************
7637 * freetype_FontIsLinked
7639 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7641 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7646 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7647 return dev
->funcs
->pFontIsLinked( dev
);
7651 EnterCriticalSection( &freetype_cs
);
7652 ret
= !list_empty(&physdev
->font
->child_fonts
);
7653 LeaveCriticalSection( &freetype_cs
);
7657 /*************************************************************************
7658 * GetRasterizerCaps (GDI32.@)
7660 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7662 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7663 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7664 lprs
->nLanguageID
= 0;
7668 /*************************************************************
7669 * freetype_GdiRealizationInfo
7671 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7673 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7674 realization_info_t
*info
= ptr
;
7678 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7679 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7682 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7685 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7688 info
->cache_num
= physdev
->font
->cache_num
;
7689 info
->unknown2
= -1;
7693 /*************************************************************************
7694 * Kerning support for TrueType fonts
7696 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7698 struct TT_kern_table
7704 struct TT_kern_subtable
7713 USHORT horizontal
: 1;
7715 USHORT cross_stream
: 1;
7716 USHORT override
: 1;
7717 USHORT reserved1
: 4;
7723 struct TT_format0_kern_subtable
7727 USHORT entrySelector
;
7738 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7739 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7740 const USHORT
*glyph_to_char
,
7741 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7744 const struct TT_kern_pair
*tt_kern_pair
;
7746 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7748 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7750 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7751 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7752 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7754 if (!kern_pair
|| !cPairs
)
7757 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7759 nPairs
= min(nPairs
, cPairs
);
7761 for (i
= 0; i
< nPairs
; i
++)
7763 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7764 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7765 /* this algorithm appears to better match what Windows does */
7766 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7767 if (kern_pair
->iKernAmount
< 0)
7769 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7770 kern_pair
->iKernAmount
-= font
->ppem
;
7772 else if (kern_pair
->iKernAmount
> 0)
7774 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7775 kern_pair
->iKernAmount
+= font
->ppem
;
7777 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7779 TRACE("left %u right %u value %d\n",
7780 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7784 TRACE("copied %u entries\n", nPairs
);
7788 /*************************************************************
7789 * freetype_GetKerningPairs
7791 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7795 const struct TT_kern_table
*tt_kern_table
;
7796 const struct TT_kern_subtable
*tt_kern_subtable
;
7798 USHORT
*glyph_to_char
;
7800 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7802 if (!(font
= physdev
->font
))
7804 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7805 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7809 EnterCriticalSection( &freetype_cs
);
7810 if (font
->total_kern_pairs
!= (DWORD
)-1)
7812 if (cPairs
&& kern_pair
)
7814 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7815 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7817 else cPairs
= font
->total_kern_pairs
;
7819 LeaveCriticalSection( &freetype_cs
);
7823 font
->total_kern_pairs
= 0;
7825 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7827 if (length
== GDI_ERROR
)
7829 TRACE("no kerning data in the font\n");
7830 LeaveCriticalSection( &freetype_cs
);
7834 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7837 WARN("Out of memory\n");
7838 LeaveCriticalSection( &freetype_cs
);
7842 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7844 /* build a glyph index to char code map */
7845 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7848 WARN("Out of memory allocating a glyph index to char code map\n");
7849 HeapFree(GetProcessHeap(), 0, buf
);
7850 LeaveCriticalSection( &freetype_cs
);
7854 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7860 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7862 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7863 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7867 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7869 /* FIXME: This doesn't match what Windows does: it does some fancy
7870 * things with duplicate glyph index to char code mappings, while
7871 * we just avoid overriding existing entries.
7873 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7874 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7876 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7883 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7884 for (n
= 0; n
<= 65535; n
++)
7885 glyph_to_char
[n
] = (USHORT
)n
;
7888 tt_kern_table
= buf
;
7889 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7890 TRACE("version %u, nTables %u\n",
7891 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7893 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7895 for (i
= 0; i
< nTables
; i
++)
7897 struct TT_kern_subtable tt_kern_subtable_copy
;
7899 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7900 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7901 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7903 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7904 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7905 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7907 /* According to the TrueType specification this is the only format
7908 * that will be properly interpreted by Windows and OS/2
7910 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7912 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7914 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7915 glyph_to_char
, NULL
, 0);
7916 font
->total_kern_pairs
+= new_chunk
;
7918 if (!font
->kern_pairs
)
7919 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7920 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7922 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7923 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7925 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7926 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7929 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7931 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7934 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7935 HeapFree(GetProcessHeap(), 0, buf
);
7937 if (cPairs
&& kern_pair
)
7939 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7940 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7942 else cPairs
= font
->total_kern_pairs
;
7944 LeaveCriticalSection( &freetype_cs
);
7948 static const struct gdi_dc_funcs freetype_funcs
=
7950 NULL
, /* pAbortDoc */
7951 NULL
, /* pAbortPath */
7952 NULL
, /* pAlphaBlend */
7953 NULL
, /* pAngleArc */
7956 NULL
, /* pBeginPath */
7957 NULL
, /* pBlendImage */
7959 NULL
, /* pCloseFigure */
7960 NULL
, /* pCreateCompatibleDC */
7961 freetype_CreateDC
, /* pCreateDC */
7962 freetype_DeleteDC
, /* pDeleteDC */
7963 NULL
, /* pDeleteObject */
7964 NULL
, /* pDeviceCapabilities */
7965 NULL
, /* pEllipse */
7967 NULL
, /* pEndPage */
7968 NULL
, /* pEndPath */
7969 freetype_EnumFonts
, /* pEnumFonts */
7970 NULL
, /* pEnumICMProfiles */
7971 NULL
, /* pExcludeClipRect */
7972 NULL
, /* pExtDeviceMode */
7973 NULL
, /* pExtEscape */
7974 NULL
, /* pExtFloodFill */
7975 NULL
, /* pExtSelectClipRgn */
7976 NULL
, /* pExtTextOut */
7977 NULL
, /* pFillPath */
7978 NULL
, /* pFillRgn */
7979 NULL
, /* pFlattenPath */
7980 freetype_FontIsLinked
, /* pFontIsLinked */
7981 NULL
, /* pFrameRgn */
7982 NULL
, /* pGdiComment */
7983 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7984 NULL
, /* pGetBoundsRect */
7985 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7986 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7987 freetype_GetCharWidth
, /* pGetCharWidth */
7988 NULL
, /* pGetDeviceCaps */
7989 NULL
, /* pGetDeviceGammaRamp */
7990 freetype_GetFontData
, /* pGetFontData */
7991 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7992 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7993 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7994 NULL
, /* pGetICMProfile */
7995 NULL
, /* pGetImage */
7996 freetype_GetKerningPairs
, /* pGetKerningPairs */
7997 NULL
, /* pGetNearestColor */
7998 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7999 NULL
, /* pGetPixel */
8000 NULL
, /* pGetSystemPaletteEntries */
8001 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8002 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8003 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8004 freetype_GetTextFace
, /* pGetTextFace */
8005 freetype_GetTextMetrics
, /* pGetTextMetrics */
8006 NULL
, /* pGradientFill */
8007 NULL
, /* pIntersectClipRect */
8008 NULL
, /* pInvertRgn */
8010 NULL
, /* pModifyWorldTransform */
8012 NULL
, /* pOffsetClipRgn */
8013 NULL
, /* pOffsetViewportOrg */
8014 NULL
, /* pOffsetWindowOrg */
8015 NULL
, /* pPaintRgn */
8018 NULL
, /* pPolyBezier */
8019 NULL
, /* pPolyBezierTo */
8020 NULL
, /* pPolyDraw */
8021 NULL
, /* pPolyPolygon */
8022 NULL
, /* pPolyPolyline */
8023 NULL
, /* pPolygon */
8024 NULL
, /* pPolyline */
8025 NULL
, /* pPolylineTo */
8026 NULL
, /* pPutImage */
8027 NULL
, /* pRealizeDefaultPalette */
8028 NULL
, /* pRealizePalette */
8029 NULL
, /* pRectangle */
8030 NULL
, /* pResetDC */
8031 NULL
, /* pRestoreDC */
8032 NULL
, /* pRoundRect */
8034 NULL
, /* pScaleViewportExt */
8035 NULL
, /* pScaleWindowExt */
8036 NULL
, /* pSelectBitmap */
8037 NULL
, /* pSelectBrush */
8038 NULL
, /* pSelectClipPath */
8039 freetype_SelectFont
, /* pSelectFont */
8040 NULL
, /* pSelectPalette */
8041 NULL
, /* pSelectPen */
8042 NULL
, /* pSetArcDirection */
8043 NULL
, /* pSetBkColor */
8044 NULL
, /* pSetBkMode */
8045 NULL
, /* pSetDCBrushColor */
8046 NULL
, /* pSetDCPenColor */
8047 NULL
, /* pSetDIBColorTable */
8048 NULL
, /* pSetDIBitsToDevice */
8049 NULL
, /* pSetDeviceClipping */
8050 NULL
, /* pSetDeviceGammaRamp */
8051 NULL
, /* pSetLayout */
8052 NULL
, /* pSetMapMode */
8053 NULL
, /* pSetMapperFlags */
8054 NULL
, /* pSetPixel */
8055 NULL
, /* pSetPolyFillMode */
8056 NULL
, /* pSetROP2 */
8057 NULL
, /* pSetRelAbs */
8058 NULL
, /* pSetStretchBltMode */
8059 NULL
, /* pSetTextAlign */
8060 NULL
, /* pSetTextCharacterExtra */
8061 NULL
, /* pSetTextColor */
8062 NULL
, /* pSetTextJustification */
8063 NULL
, /* pSetViewportExt */
8064 NULL
, /* pSetViewportOrg */
8065 NULL
, /* pSetWindowExt */
8066 NULL
, /* pSetWindowOrg */
8067 NULL
, /* pSetWorldTransform */
8068 NULL
, /* pStartDoc */
8069 NULL
, /* pStartPage */
8070 NULL
, /* pStretchBlt */
8071 NULL
, /* pStretchDIBits */
8072 NULL
, /* pStrokeAndFillPath */
8073 NULL
, /* pStrokePath */
8074 NULL
, /* pUnrealizePalette */
8075 NULL
, /* pWidenPath */
8076 NULL
, /* wine_get_wgl_driver */
8077 GDI_PRIORITY_FONT_DRV
/* priority */
8080 #else /* HAVE_FREETYPE */
8082 /*************************************************************************/
8084 BOOL
WineEngInit(void)
8089 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8091 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8095 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8097 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8101 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8103 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8107 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8108 LPCWSTR font_file
, LPCWSTR font_path
)
8114 /*************************************************************************
8115 * GetRasterizerCaps (GDI32.@)
8117 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8119 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8121 lprs
->nLanguageID
= 0;
8125 #endif /* HAVE_FREETYPE */