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 /*************************************************************
5821 * freetype_GetGlyphIndices
5823 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5825 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5828 BOOL got_default
= FALSE
;
5832 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5833 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5836 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5838 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5843 EnterCriticalSection( &freetype_cs
);
5845 for(i
= 0; i
< count
; i
++)
5847 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5852 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5854 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5855 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5860 get_text_metrics(physdev
->font
, &textm
);
5861 default_char
= textm
.tmDefaultChar
;
5865 pgi
[i
] = default_char
;
5868 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
5870 LeaveCriticalSection( &freetype_cs
);
5874 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5876 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5877 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5880 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5882 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5883 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5886 static inline BYTE
get_max_level( UINT format
)
5890 case GGO_GRAY2_BITMAP
: return 4;
5891 case GGO_GRAY4_BITMAP
: return 16;
5892 case GGO_GRAY8_BITMAP
: return 64;
5897 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5899 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5900 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
5903 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5904 FT_Face ft_face
= incoming_font
->ft_face
;
5905 GdiFont
*font
= incoming_font
;
5906 FT_Glyph_Metrics metrics
;
5907 FT_UInt glyph_index
;
5908 DWORD width
, height
, pitch
, needed
= 0;
5909 FT_Bitmap ft_bitmap
;
5911 INT left
, right
, top
= 0, bottom
= 0, adv
;
5913 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5914 double widthRatio
= 1.0;
5915 FT_Matrix transMat
= identityMat
;
5916 FT_Matrix transMatUnrotated
;
5917 BOOL needsTransform
= FALSE
;
5918 BOOL tategaki
= (font
->name
[0] == '@');
5919 UINT original_index
;
5920 LONG avgAdvance
= 0;
5923 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5924 buflen
, buf
, lpmat
);
5926 TRACE("font transform %f %f %f %f\n",
5927 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5928 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5930 if(format
& GGO_GLYPH_INDEX
) {
5931 glyph_index
= glyph
;
5932 original_index
= glyph
;
5933 format
&= ~GGO_GLYPH_INDEX
;
5935 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5936 ft_face
= font
->ft_face
;
5937 original_index
= glyph_index
;
5940 if(format
& GGO_UNHINTED
) {
5941 load_flags
|= FT_LOAD_NO_HINTING
;
5942 format
&= ~GGO_UNHINTED
;
5945 /* tategaki never appears to happen to lower glyph index */
5946 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5949 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5950 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5951 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5952 font
->gmsize
* sizeof(GM
*));
5954 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5955 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5957 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5958 *abc
= FONT_GM(font
,original_index
)->abc
;
5959 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5960 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5961 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5962 return 1; /* FIXME */
5966 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5967 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5969 /* Scaling factor */
5974 get_text_metrics(font
, &tm
);
5976 widthRatio
= (double)font
->aveWidth
;
5977 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5980 widthRatio
= font
->scale_y
;
5982 /* Scaling transform */
5983 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5986 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5989 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5991 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5992 needsTransform
= TRUE
;
5995 /* Slant transform */
5996 if (font
->fake_italic
) {
5999 slantMat
.xx
= (1 << 16);
6000 slantMat
.xy
= ((1 << 16) >> 2);
6002 slantMat
.yy
= (1 << 16);
6003 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6004 needsTransform
= TRUE
;
6007 /* Rotation transform */
6008 transMatUnrotated
= transMat
;
6009 if(font
->orientation
&& !tategaki
) {
6010 FT_Matrix rotationMat
;
6012 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
6013 pFT_Vector_Unit(&vecAngle
, angle
);
6014 rotationMat
.xx
= vecAngle
.x
;
6015 rotationMat
.xy
= -vecAngle
.y
;
6016 rotationMat
.yx
= -rotationMat
.xy
;
6017 rotationMat
.yy
= rotationMat
.xx
;
6019 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6020 needsTransform
= TRUE
;
6023 /* World transform */
6024 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6027 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6028 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6029 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6030 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6031 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6032 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6033 needsTransform
= TRUE
;
6036 /* Extra transformation specified by caller */
6037 if (!is_identity_MAT2(lpmat
))
6040 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6041 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6042 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6043 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6044 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6045 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6046 needsTransform
= TRUE
;
6049 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6051 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6054 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6058 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6059 * by the text metrics. The proper behavior is to clip the glyph metrics to
6060 * fit within the maximums specified in the text metrics. */
6061 metrics
= ft_face
->glyph
->metrics
;
6062 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6063 get_bitmap_text_metrics(incoming_font
)) {
6064 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6065 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6066 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6067 metrics
.horiBearingY
= top
;
6068 metrics
.height
= top
- bottom
;
6070 /* TODO: Are we supposed to clip the width as well...? */
6071 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6074 if(FT_IS_SCALABLE(incoming_font
->ft_face
)) {
6076 if (get_text_metrics(incoming_font
, &tm
) &&
6077 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6078 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6079 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6081 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6082 TRACE("Fixed-pitch full-width character detected\n");
6084 avgAdvance
= 0; /* cancel this feature */
6088 if(!needsTransform
) {
6089 left
= (INT
)(metrics
.horiBearingX
) & -64;
6090 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6092 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6094 adv
= (INT
)avgAdvance
* 2;
6096 top
= (metrics
.horiBearingY
+ 63) & -64;
6097 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6098 lpgm
->gmCellIncX
= adv
;
6099 lpgm
->gmCellIncY
= 0;
6106 for(xc
= 0; xc
< 2; xc
++) {
6107 for(yc
= 0; yc
< 2; yc
++) {
6108 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6109 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6110 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6111 pFT_Vector_Transform(&vec
, &transMat
);
6112 if(xc
== 0 && yc
== 0) {
6113 left
= right
= vec
.x
;
6114 top
= bottom
= vec
.y
;
6116 if(vec
.x
< left
) left
= vec
.x
;
6117 else if(vec
.x
> right
) right
= vec
.x
;
6118 if(vec
.y
< bottom
) bottom
= vec
.y
;
6119 else if(vec
.y
> top
) top
= vec
.y
;
6124 right
= (right
+ 63) & -64;
6125 bottom
= bottom
& -64;
6126 top
= (top
+ 63) & -64;
6128 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6129 vec
.x
= metrics
.horiAdvance
;
6131 pFT_Vector_Transform(&vec
, &transMat
);
6132 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6133 if (!avgAdvance
|| vec
.y
)
6134 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6136 vec
.x
= incoming_font
->ntmAvgWidth
;
6138 pFT_Vector_Transform(&vec
, &transMat
);
6139 lpgm
->gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6142 vec
.x
= metrics
.horiAdvance
;
6144 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6145 if (!avgAdvance
|| vec
.y
)
6146 adv
= (vec
.x
+63) >> 6;
6148 vec
.x
= incoming_font
->ntmAvgWidth
;
6150 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6151 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6155 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6156 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6157 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
6158 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
6159 abc
->abcA
= left
>> 6;
6160 abc
->abcB
= (right
- left
) >> 6;
6161 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6163 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6164 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6165 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6167 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6168 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6170 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6171 FONT_GM(font
,original_index
)->abc
= *abc
;
6172 FONT_GM(font
,original_index
)->init
= TRUE
;
6175 if(format
== GGO_METRICS
)
6177 return 1; /* FIXME */
6180 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6181 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6183 TRACE("loaded a bitmap\n");
6189 width
= lpgm
->gmBlackBoxX
;
6190 height
= lpgm
->gmBlackBoxY
;
6191 pitch
= ((width
+ 31) >> 5) << 2;
6192 needed
= pitch
* height
;
6194 if(!buf
|| !buflen
) break;
6196 switch(ft_face
->glyph
->format
) {
6197 case ft_glyph_format_bitmap
:
6199 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6200 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6201 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6203 memcpy(dst
, src
, w
);
6204 src
+= ft_face
->glyph
->bitmap
.pitch
;
6210 case ft_glyph_format_outline
:
6211 ft_bitmap
.width
= width
;
6212 ft_bitmap
.rows
= height
;
6213 ft_bitmap
.pitch
= pitch
;
6214 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6215 ft_bitmap
.buffer
= buf
;
6218 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6220 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6222 /* Note: FreeType will only set 'black' bits for us. */
6223 memset(buf
, 0, needed
);
6224 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6228 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6233 case GGO_GRAY2_BITMAP
:
6234 case GGO_GRAY4_BITMAP
:
6235 case GGO_GRAY8_BITMAP
:
6236 case WINE_GGO_GRAY16_BITMAP
:
6238 unsigned int max_level
, row
, col
;
6241 width
= lpgm
->gmBlackBoxX
;
6242 height
= lpgm
->gmBlackBoxY
;
6243 pitch
= (width
+ 3) / 4 * 4;
6244 needed
= pitch
* height
;
6246 if(!buf
|| !buflen
) break;
6248 max_level
= get_max_level( format
);
6250 switch(ft_face
->glyph
->format
) {
6251 case ft_glyph_format_bitmap
:
6253 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6254 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6256 memset( buf
, 0, needed
);
6258 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6259 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6260 src
+= ft_face
->glyph
->bitmap
.pitch
;
6265 case ft_glyph_format_outline
:
6267 ft_bitmap
.width
= width
;
6268 ft_bitmap
.rows
= height
;
6269 ft_bitmap
.pitch
= pitch
;
6270 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6271 ft_bitmap
.buffer
= buf
;
6274 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6276 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6278 memset(ft_bitmap
.buffer
, 0, buflen
);
6280 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6282 if (max_level
!= 255)
6284 for (row
= 0, start
= buf
; row
< height
; row
++)
6286 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6287 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6295 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6301 case WINE_GGO_HRGB_BITMAP
:
6302 case WINE_GGO_HBGR_BITMAP
:
6303 case WINE_GGO_VRGB_BITMAP
:
6304 case WINE_GGO_VBGR_BITMAP
:
6305 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6307 switch (ft_face
->glyph
->format
)
6309 case FT_GLYPH_FORMAT_BITMAP
:
6314 width
= lpgm
->gmBlackBoxX
;
6315 height
= lpgm
->gmBlackBoxY
;
6317 needed
= pitch
* height
;
6319 if (!buf
|| !buflen
) break;
6321 memset(buf
, 0, buflen
);
6323 src
= ft_face
->glyph
->bitmap
.buffer
;
6324 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6326 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6329 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6331 if ( src
[x
/ 8] & masks
[x
% 8] )
6332 ((unsigned int *)dst
)[x
] = ~0u;
6341 case FT_GLYPH_FORMAT_OUTLINE
:
6345 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6346 INT x_shift
, y_shift
;
6348 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6349 FT_Render_Mode render_mode
=
6350 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6351 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6353 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6355 if ( render_mode
== FT_RENDER_MODE_LCD
)
6357 lpgm
->gmBlackBoxX
+= 2;
6358 lpgm
->gmptGlyphOrigin
.x
-= 1;
6362 lpgm
->gmBlackBoxY
+= 2;
6363 lpgm
->gmptGlyphOrigin
.y
+= 1;
6367 width
= lpgm
->gmBlackBoxX
;
6368 height
= lpgm
->gmBlackBoxY
;
6370 needed
= pitch
* height
;
6372 if (!buf
|| !buflen
) break;
6374 memset(buf
, 0, buflen
);
6376 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6378 if ( needsTransform
)
6379 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6381 if ( pFT_Library_SetLcdFilter
)
6382 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6383 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6385 src
= ft_face
->glyph
->bitmap
.buffer
;
6386 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6387 src_width
= ft_face
->glyph
->bitmap
.width
;
6388 src_height
= ft_face
->glyph
->bitmap
.rows
;
6390 if ( render_mode
== FT_RENDER_MODE_LCD
)
6398 rgb_interval
= src_pitch
;
6403 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6406 src
+= hmul
* -x_shift
;
6407 src_width
-= hmul
* -x_shift
;
6409 else if ( x_shift
> 0 )
6415 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6418 src
+= src_pitch
* vmul
* -y_shift
;
6419 src_height
-= vmul
* -y_shift
;
6421 else if ( y_shift
> 0 )
6423 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
6427 width
= min( width
, src_width
/ hmul
);
6428 height
= min( height
, src_height
/ vmul
);
6432 for ( x
= 0; x
< width
; x
++ )
6436 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6437 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6438 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6439 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6443 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6444 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6445 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6446 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6449 src
+= src_pitch
* vmul
;
6450 dst
+= pitch
/ sizeof(*dst
);
6457 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6469 int contour
, point
= 0, first_pt
;
6470 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6471 TTPOLYGONHEADER
*pph
;
6473 DWORD pph_start
, cpfx
, type
;
6475 if(buflen
== 0) buf
= NULL
;
6477 if (needsTransform
&& buf
) {
6478 pFT_Outline_Transform(outline
, &transMat
);
6481 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6482 /* Ignore contours containing one point */
6483 if(point
== outline
->contours
[contour
]) {
6489 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6492 pph
->dwType
= TT_POLYGON_TYPE
;
6493 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6495 needed
+= sizeof(*pph
);
6497 while(point
<= outline
->contours
[contour
]) {
6498 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6499 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6500 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6504 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6507 } while(point
<= outline
->contours
[contour
] &&
6508 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6509 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6510 /* At the end of a contour Windows adds the start point, but
6512 if(point
> outline
->contours
[contour
] &&
6513 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6515 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6517 } else if(point
<= outline
->contours
[contour
] &&
6518 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6519 /* add closing pt for bezier */
6521 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6529 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6532 pph
->cb
= needed
- pph_start
;
6538 /* Convert the quadratic Beziers to cubic Beziers.
6539 The parametric eqn for a cubic Bezier is, from PLRM:
6540 r(t) = at^3 + bt^2 + ct + r0
6541 with the control points:
6546 A quadratic Bezier has the form:
6547 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6549 So equating powers of t leads to:
6550 r1 = 2/3 p1 + 1/3 p0
6551 r2 = 2/3 p1 + 1/3 p2
6552 and of course r0 = p0, r3 = p2
6555 int contour
, point
= 0, first_pt
;
6556 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6557 TTPOLYGONHEADER
*pph
;
6559 DWORD pph_start
, cpfx
, type
;
6560 FT_Vector cubic_control
[4];
6561 if(buflen
== 0) buf
= NULL
;
6563 if (needsTransform
&& buf
) {
6564 pFT_Outline_Transform(outline
, &transMat
);
6567 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6569 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6572 pph
->dwType
= TT_POLYGON_TYPE
;
6573 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6575 needed
+= sizeof(*pph
);
6577 while(point
<= outline
->contours
[contour
]) {
6578 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6579 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6580 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6583 if(type
== TT_PRIM_LINE
) {
6585 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6589 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6592 /* FIXME: Possible optimization in endpoint calculation
6593 if there are two consecutive curves */
6594 cubic_control
[0] = outline
->points
[point
-1];
6595 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6596 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6597 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6598 cubic_control
[0].x
>>= 1;
6599 cubic_control
[0].y
>>= 1;
6601 if(point
+1 > outline
->contours
[contour
])
6602 cubic_control
[3] = outline
->points
[first_pt
];
6604 cubic_control
[3] = outline
->points
[point
+1];
6605 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6606 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6607 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6608 cubic_control
[3].x
>>= 1;
6609 cubic_control
[3].y
>>= 1;
6612 /* r1 = 1/3 p0 + 2/3 p1
6613 r2 = 1/3 p2 + 2/3 p1 */
6614 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6615 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6616 cubic_control
[2] = cubic_control
[1];
6617 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6618 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6619 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6620 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6622 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6623 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6624 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6629 } while(point
<= outline
->contours
[contour
] &&
6630 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6631 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6632 /* At the end of a contour Windows adds the start point,
6633 but only for Beziers and we've already done that.
6635 if(point
<= outline
->contours
[contour
] &&
6636 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6637 /* This is the closing pt of a bezier, but we've already
6638 added it, so just inc point and carry on */
6645 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6648 pph
->cb
= needed
- pph_start
;
6654 FIXME("Unsupported format %d\n", format
);
6660 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6662 FT_Face ft_face
= font
->ft_face
;
6663 FT_WinFNT_HeaderRec winfnt_header
;
6664 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6665 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6666 font
->potm
->otmSize
= size
;
6668 #define TM font->potm->otmTextMetrics
6669 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6671 TM
.tmHeight
= winfnt_header
.pixel_height
;
6672 TM
.tmAscent
= winfnt_header
.ascent
;
6673 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6674 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6675 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6676 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6677 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6678 TM
.tmWeight
= winfnt_header
.weight
;
6680 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6681 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6682 TM
.tmFirstChar
= winfnt_header
.first_char
;
6683 TM
.tmLastChar
= winfnt_header
.last_char
;
6684 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6685 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6686 TM
.tmItalic
= winfnt_header
.italic
;
6687 TM
.tmUnderlined
= font
->underline
;
6688 TM
.tmStruckOut
= font
->strikeout
;
6689 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6690 TM
.tmCharSet
= winfnt_header
.charset
;
6694 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6695 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6696 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6697 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6698 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6699 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6700 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6701 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6703 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6704 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6706 TM
.tmLastChar
= 255;
6707 TM
.tmDefaultChar
= 32;
6708 TM
.tmBreakChar
= 32;
6709 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6710 TM
.tmUnderlined
= font
->underline
;
6711 TM
.tmStruckOut
= font
->strikeout
;
6712 /* NB inverted meaning of TMPF_FIXED_PITCH */
6713 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6714 TM
.tmCharSet
= font
->charset
;
6722 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6724 double scale_x
, scale_y
;
6728 scale_x
= (double)font
->aveWidth
;
6729 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6732 scale_x
= font
->scale_y
;
6734 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6735 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6737 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6738 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6740 SCALE_Y(ptm
->tmHeight
);
6741 SCALE_Y(ptm
->tmAscent
);
6742 SCALE_Y(ptm
->tmDescent
);
6743 SCALE_Y(ptm
->tmInternalLeading
);
6744 SCALE_Y(ptm
->tmExternalLeading
);
6745 SCALE_Y(ptm
->tmOverhang
);
6747 SCALE_X(ptm
->tmAveCharWidth
);
6748 SCALE_X(ptm
->tmMaxCharWidth
);
6754 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6756 double scale_x
, scale_y
;
6760 scale_x
= (double)font
->aveWidth
;
6761 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6764 scale_x
= font
->scale_y
;
6766 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6767 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6769 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6771 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6772 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6774 SCALE_Y(potm
->otmAscent
);
6775 SCALE_Y(potm
->otmDescent
);
6776 SCALE_Y(potm
->otmLineGap
);
6777 SCALE_Y(potm
->otmsCapEmHeight
);
6778 SCALE_Y(potm
->otmsXHeight
);
6779 SCALE_Y(potm
->otmrcFontBox
.top
);
6780 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6781 SCALE_X(potm
->otmrcFontBox
.left
);
6782 SCALE_X(potm
->otmrcFontBox
.right
);
6783 SCALE_Y(potm
->otmMacAscent
);
6784 SCALE_Y(potm
->otmMacDescent
);
6785 SCALE_Y(potm
->otmMacLineGap
);
6786 SCALE_X(potm
->otmptSubscriptSize
.x
);
6787 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6788 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6789 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6790 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6791 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6792 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6793 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6794 SCALE_Y(potm
->otmsStrikeoutSize
);
6795 SCALE_Y(potm
->otmsStrikeoutPosition
);
6796 SCALE_Y(potm
->otmsUnderscoreSize
);
6797 SCALE_Y(potm
->otmsUnderscorePosition
);
6803 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6807 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6809 /* Make sure that the font has sane width/height ratio */
6812 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6814 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6819 *ptm
= font
->potm
->otmTextMetrics
;
6820 scale_font_metrics(font
, ptm
);
6824 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6828 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6830 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6836 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6839 FT_Face ft_face
= font
->ft_face
;
6840 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
6842 TT_HoriHeader
*pHori
;
6843 TT_Postscript
*pPost
;
6845 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
6847 INT ascent
, descent
;
6849 TRACE("font=%p\n", font
);
6851 if(!FT_IS_SCALABLE(ft_face
))
6854 needed
= sizeof(*font
->potm
);
6856 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6857 family_nameW
= strdupW(font
->name
);
6859 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
6861 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6864 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6865 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
6867 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
6869 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
6871 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6874 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6875 face_nameW
= strdupW(font
->name
);
6877 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
6878 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
6880 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
6882 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6885 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
6886 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6887 full_nameW
= strdupW(fake_nameW
);
6889 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
6891 /* These names should be read from the TT name table */
6893 /* length of otmpFamilyName */
6896 /* length of otmpFaceName */
6899 /* length of otmpStyleName */
6902 /* length of otmpFullName */
6906 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
6908 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6910 FIXME("Can't find OS/2 table - not TT font?\n");
6914 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6916 FIXME("Can't find HHEA table - not TT font?\n");
6920 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6922 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",
6923 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6924 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6925 pOS2
->xAvgCharWidth
,
6926 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6927 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6928 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6930 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6931 font
->potm
->otmSize
= needed
;
6933 #define TM font->potm->otmTextMetrics
6935 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6936 ascent
= pHori
->Ascender
;
6937 descent
= -pHori
->Descender
;
6939 ascent
= pOS2
->usWinAscent
;
6940 descent
= pOS2
->usWinDescent
;
6943 font
->ntmCellHeight
= ascent
+ descent
;
6944 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6946 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6947 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6950 TM
.tmAscent
= font
->yMax
;
6951 TM
.tmDescent
= -font
->yMin
;
6952 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6954 TM
.tmAscent
= SCALE_Y(ascent
);
6955 TM
.tmDescent
= SCALE_Y(descent
);
6956 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
6959 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6962 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6964 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
6965 ((ascent
+ descent
) -
6966 (pHori
->Ascender
- pHori
->Descender
))));
6968 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
6969 if (TM
.tmAveCharWidth
== 0) {
6970 TM
.tmAveCharWidth
= 1;
6972 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
6973 TM
.tmWeight
= FW_REGULAR
;
6974 if (font
->fake_bold
)
6975 TM
.tmWeight
= FW_BOLD
;
6978 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6980 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6981 TM
.tmWeight
= pOS2
->usWeightClass
;
6983 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6984 TM
.tmWeight
= pOS2
->usWeightClass
;
6987 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6988 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6989 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6990 * symbol range to 0 - f0ff
6993 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6998 case 1257: /* Baltic */
6999 TM
.tmLastChar
= 0xf8fd;
7002 TM
.tmLastChar
= 0xf0ff;
7004 TM
.tmBreakChar
= 0x20;
7005 TM
.tmDefaultChar
= 0x1f;
7009 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7010 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7012 if(pOS2
->usFirstCharIndex
<= 1)
7013 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7014 else if (pOS2
->usFirstCharIndex
> 0xff)
7015 TM
.tmBreakChar
= 0x20;
7017 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7018 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7020 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7021 TM
.tmUnderlined
= font
->underline
;
7022 TM
.tmStruckOut
= font
->strikeout
;
7024 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7025 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7026 (pOS2
->version
== 0xFFFFU
||
7027 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7028 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7030 TM
.tmPitchAndFamily
= 0;
7032 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7034 case PAN_FAMILY_SCRIPT
:
7035 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7038 case PAN_FAMILY_DECORATIVE
:
7039 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7044 case PAN_FAMILY_TEXT_DISPLAY
:
7045 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7046 /* which is clearly not what the panose spec says. */
7048 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7049 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7050 TM
.tmPitchAndFamily
= FF_MODERN
;
7053 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7058 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7061 case PAN_SERIF_COVE
:
7062 case PAN_SERIF_OBTUSE_COVE
:
7063 case PAN_SERIF_SQUARE_COVE
:
7064 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7065 case PAN_SERIF_SQUARE
:
7066 case PAN_SERIF_THIN
:
7067 case PAN_SERIF_BONE
:
7068 case PAN_SERIF_EXAGGERATED
:
7069 case PAN_SERIF_TRIANGLE
:
7070 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7073 case PAN_SERIF_NORMAL_SANS
:
7074 case PAN_SERIF_OBTUSE_SANS
:
7075 case PAN_SERIF_PERP_SANS
:
7076 case PAN_SERIF_FLARED
:
7077 case PAN_SERIF_ROUNDED
:
7078 TM
.tmPitchAndFamily
|= FF_SWISS
;
7085 if(FT_IS_SCALABLE(ft_face
))
7086 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7088 if(FT_IS_SFNT(ft_face
))
7090 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7091 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7093 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7096 TM
.tmCharSet
= font
->charset
;
7098 font
->potm
->otmFiller
= 0;
7099 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7100 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7101 font
->potm
->otmfsType
= pOS2
->fsType
;
7102 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7103 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7104 font
->potm
->otmItalicAngle
= 0; /* POST table */
7105 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7106 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7107 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7108 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7109 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7110 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7111 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7112 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7113 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7114 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7115 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7116 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7117 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7118 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7119 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7120 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7121 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7122 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7123 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7124 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7125 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7126 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7127 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7128 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7130 font
->potm
->otmsUnderscoreSize
= 0;
7131 font
->potm
->otmsUnderscorePosition
= 0;
7133 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7134 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7140 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7141 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7142 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7143 strcpyW((WCHAR
*)cp
, family_nameW
);
7145 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7146 strcpyW((WCHAR
*)cp
, style_nameW
);
7148 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7149 strcpyW((WCHAR
*)cp
, face_nameW
);
7151 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7152 strcpyW((WCHAR
*)cp
, full_nameW
);
7156 HeapFree(GetProcessHeap(), 0, style_nameW
);
7157 HeapFree(GetProcessHeap(), 0, family_nameW
);
7158 HeapFree(GetProcessHeap(), 0, face_nameW
);
7159 HeapFree(GetProcessHeap(), 0, full_nameW
);
7163 /*************************************************************
7164 * freetype_GetGlyphOutline
7166 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7167 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7169 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7175 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7176 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7180 EnterCriticalSection( &freetype_cs
);
7181 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7182 LeaveCriticalSection( &freetype_cs
);
7186 /*************************************************************
7187 * freetype_GetTextMetrics
7189 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7191 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7196 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7197 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7201 EnterCriticalSection( &freetype_cs
);
7202 ret
= get_text_metrics( physdev
->font
, metrics
);
7203 LeaveCriticalSection( &freetype_cs
);
7207 /*************************************************************
7208 * freetype_GetOutlineTextMetrics
7210 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7212 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7217 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7218 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7221 TRACE("font=%p\n", physdev
->font
);
7223 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7226 EnterCriticalSection( &freetype_cs
);
7228 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7230 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7232 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7233 scale_outline_font_metrics(physdev
->font
, potm
);
7235 ret
= physdev
->font
->potm
->otmSize
;
7237 LeaveCriticalSection( &freetype_cs
);
7241 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7243 child
->font
= alloc_font();
7244 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7245 if(!child
->font
->ft_face
)
7247 free_font(child
->font
);
7252 child
->font
->font_desc
= font
->font_desc
;
7253 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7254 child
->font
->orientation
= font
->orientation
;
7255 child
->font
->scale_y
= font
->scale_y
;
7256 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7257 child
->font
->base_font
= font
;
7258 TRACE("created child font %p for base %p\n", child
->font
, font
);
7262 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
7265 CHILD_FONT
*child_font
;
7268 font
= font
->base_font
;
7270 *linked_font
= font
;
7272 if((*glyph
= get_glyph_index(font
, c
)))
7274 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7278 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7280 if(!child_font
->font
)
7281 if(!load_child_font(font
, child_font
))
7284 if(!child_font
->font
->ft_face
)
7286 g
= get_glyph_index(child_font
->font
, c
);
7287 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7291 *linked_font
= child_font
->font
;
7298 /*************************************************************
7299 * freetype_GetCharWidth
7301 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7303 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7307 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7311 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7312 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7315 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7318 EnterCriticalSection( &freetype_cs
);
7319 for(c
= firstChar
; c
<= lastChar
; c
++) {
7320 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7321 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7323 LeaveCriticalSection( &freetype_cs
);
7327 /*************************************************************
7328 * freetype_GetCharABCWidths
7330 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7332 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7335 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7339 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7340 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7343 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7346 EnterCriticalSection( &freetype_cs
);
7348 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7349 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7351 LeaveCriticalSection( &freetype_cs
);
7355 /*************************************************************
7356 * freetype_GetCharABCWidthsI
7358 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7360 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7363 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7367 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7368 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7371 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7375 EnterCriticalSection( &freetype_cs
);
7377 for(c
= 0; c
< count
; c
++, buffer
++)
7378 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7379 &gm
, buffer
, 0, NULL
, &identity
);
7381 LeaveCriticalSection( &freetype_cs
);
7385 /*************************************************************
7386 * freetype_GetTextExtentExPoint
7388 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7390 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7394 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7398 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7399 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7402 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7405 EnterCriticalSection( &freetype_cs
);
7407 for (idx
= pos
= 0; idx
< count
; idx
++)
7409 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7410 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7414 LeaveCriticalSection( &freetype_cs
);
7418 /*************************************************************
7419 * freetype_GetTextExtentExPointI
7421 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7423 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7427 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7431 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7432 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7435 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7438 EnterCriticalSection( &freetype_cs
);
7440 for (idx
= pos
= 0; idx
< count
; idx
++)
7442 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7443 &gm
, &abc
, 0, NULL
, &identity
);
7444 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7448 LeaveCriticalSection( &freetype_cs
);
7452 /*************************************************************
7453 * freetype_GetFontData
7455 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7457 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7461 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7462 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7465 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7466 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7467 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7469 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7472 /*************************************************************
7473 * freetype_GetTextFace
7475 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7478 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7482 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7483 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7486 n
= strlenW(physdev
->font
->name
) + 1;
7489 lstrcpynW(str
, physdev
->font
->name
, count
);
7495 /*************************************************************
7496 * freetype_GetTextCharsetInfo
7498 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7500 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7504 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7505 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7507 if (fs
) *fs
= physdev
->font
->fs
;
7508 return physdev
->font
->charset
;
7511 /* Retrieve a list of supported Unicode ranges for a given font.
7512 * Can be called with NULL gs to calculate the buffer size. Returns
7513 * the number of ranges found.
7515 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7517 DWORD num_ranges
= 0;
7519 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7522 FT_ULong char_code
, char_code_prev
;
7525 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7527 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7528 face
->num_glyphs
, glyph_code
, char_code
);
7530 if (!glyph_code
) return 0;
7534 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7535 gs
->ranges
[0].cGlyphs
= 0;
7536 gs
->cGlyphsSupported
= 0;
7542 if (char_code
< char_code_prev
)
7544 ERR("expected increasing char code from FT_Get_Next_Char\n");
7547 if (char_code
- char_code_prev
> 1)
7552 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7553 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7554 gs
->cGlyphsSupported
++;
7559 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7560 gs
->cGlyphsSupported
++;
7562 char_code_prev
= char_code
;
7563 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7567 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7572 /*************************************************************
7573 * freetype_GetFontUnicodeRanges
7575 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7577 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7578 DWORD size
, num_ranges
;
7582 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7583 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7586 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7587 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7590 glyphset
->cbThis
= size
;
7591 glyphset
->cRanges
= num_ranges
;
7592 glyphset
->flAccel
= 0;
7597 /*************************************************************
7598 * freetype_FontIsLinked
7600 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7602 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7607 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7608 return dev
->funcs
->pFontIsLinked( dev
);
7612 EnterCriticalSection( &freetype_cs
);
7613 ret
= !list_empty(&physdev
->font
->child_fonts
);
7614 LeaveCriticalSection( &freetype_cs
);
7618 /*************************************************************************
7619 * GetRasterizerCaps (GDI32.@)
7621 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7623 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7624 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7625 lprs
->nLanguageID
= 0;
7629 /*************************************************************
7630 * freetype_GdiRealizationInfo
7632 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7634 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7635 realization_info_t
*info
= ptr
;
7639 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7640 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7643 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7646 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7649 info
->cache_num
= physdev
->font
->cache_num
;
7650 info
->unknown2
= -1;
7654 /*************************************************************************
7655 * Kerning support for TrueType fonts
7657 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7659 struct TT_kern_table
7665 struct TT_kern_subtable
7674 USHORT horizontal
: 1;
7676 USHORT cross_stream
: 1;
7677 USHORT override
: 1;
7678 USHORT reserved1
: 4;
7684 struct TT_format0_kern_subtable
7688 USHORT entrySelector
;
7699 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7700 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7701 const USHORT
*glyph_to_char
,
7702 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7705 const struct TT_kern_pair
*tt_kern_pair
;
7707 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7709 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7711 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7712 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7713 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7715 if (!kern_pair
|| !cPairs
)
7718 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7720 nPairs
= min(nPairs
, cPairs
);
7722 for (i
= 0; i
< nPairs
; i
++)
7724 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7725 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7726 /* this algorithm appears to better match what Windows does */
7727 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7728 if (kern_pair
->iKernAmount
< 0)
7730 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7731 kern_pair
->iKernAmount
-= font
->ppem
;
7733 else if (kern_pair
->iKernAmount
> 0)
7735 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7736 kern_pair
->iKernAmount
+= font
->ppem
;
7738 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7740 TRACE("left %u right %u value %d\n",
7741 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7745 TRACE("copied %u entries\n", nPairs
);
7749 /*************************************************************
7750 * freetype_GetKerningPairs
7752 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7756 const struct TT_kern_table
*tt_kern_table
;
7757 const struct TT_kern_subtable
*tt_kern_subtable
;
7759 USHORT
*glyph_to_char
;
7761 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7763 if (!(font
= physdev
->font
))
7765 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7766 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7770 EnterCriticalSection( &freetype_cs
);
7771 if (font
->total_kern_pairs
!= (DWORD
)-1)
7773 if (cPairs
&& kern_pair
)
7775 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7776 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7778 else cPairs
= font
->total_kern_pairs
;
7780 LeaveCriticalSection( &freetype_cs
);
7784 font
->total_kern_pairs
= 0;
7786 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7788 if (length
== GDI_ERROR
)
7790 TRACE("no kerning data in the font\n");
7791 LeaveCriticalSection( &freetype_cs
);
7795 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7798 WARN("Out of memory\n");
7799 LeaveCriticalSection( &freetype_cs
);
7803 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7805 /* build a glyph index to char code map */
7806 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7809 WARN("Out of memory allocating a glyph index to char code map\n");
7810 HeapFree(GetProcessHeap(), 0, buf
);
7811 LeaveCriticalSection( &freetype_cs
);
7815 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7821 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7823 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7824 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7828 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7830 /* FIXME: This doesn't match what Windows does: it does some fancy
7831 * things with duplicate glyph index to char code mappings, while
7832 * we just avoid overriding existing entries.
7834 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7835 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7837 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7844 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7845 for (n
= 0; n
<= 65535; n
++)
7846 glyph_to_char
[n
] = (USHORT
)n
;
7849 tt_kern_table
= buf
;
7850 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7851 TRACE("version %u, nTables %u\n",
7852 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7854 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7856 for (i
= 0; i
< nTables
; i
++)
7858 struct TT_kern_subtable tt_kern_subtable_copy
;
7860 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7861 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7862 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7864 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7865 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7866 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7868 /* According to the TrueType specification this is the only format
7869 * that will be properly interpreted by Windows and OS/2
7871 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7873 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7875 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7876 glyph_to_char
, NULL
, 0);
7877 font
->total_kern_pairs
+= new_chunk
;
7879 if (!font
->kern_pairs
)
7880 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7881 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7883 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7884 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7886 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7887 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7890 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7892 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7895 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7896 HeapFree(GetProcessHeap(), 0, buf
);
7898 if (cPairs
&& kern_pair
)
7900 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7901 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7903 else cPairs
= font
->total_kern_pairs
;
7905 LeaveCriticalSection( &freetype_cs
);
7909 static const struct gdi_dc_funcs freetype_funcs
=
7911 NULL
, /* pAbortDoc */
7912 NULL
, /* pAbortPath */
7913 NULL
, /* pAlphaBlend */
7914 NULL
, /* pAngleArc */
7917 NULL
, /* pBeginPath */
7918 NULL
, /* pBlendImage */
7920 NULL
, /* pCloseFigure */
7921 NULL
, /* pCreateCompatibleDC */
7922 freetype_CreateDC
, /* pCreateDC */
7923 freetype_DeleteDC
, /* pDeleteDC */
7924 NULL
, /* pDeleteObject */
7925 NULL
, /* pDeviceCapabilities */
7926 NULL
, /* pEllipse */
7928 NULL
, /* pEndPage */
7929 NULL
, /* pEndPath */
7930 freetype_EnumFonts
, /* pEnumFonts */
7931 NULL
, /* pEnumICMProfiles */
7932 NULL
, /* pExcludeClipRect */
7933 NULL
, /* pExtDeviceMode */
7934 NULL
, /* pExtEscape */
7935 NULL
, /* pExtFloodFill */
7936 NULL
, /* pExtSelectClipRgn */
7937 NULL
, /* pExtTextOut */
7938 NULL
, /* pFillPath */
7939 NULL
, /* pFillRgn */
7940 NULL
, /* pFlattenPath */
7941 freetype_FontIsLinked
, /* pFontIsLinked */
7942 NULL
, /* pFrameRgn */
7943 NULL
, /* pGdiComment */
7944 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7945 NULL
, /* pGetBoundsRect */
7946 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7947 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7948 freetype_GetCharWidth
, /* pGetCharWidth */
7949 NULL
, /* pGetDeviceCaps */
7950 NULL
, /* pGetDeviceGammaRamp */
7951 freetype_GetFontData
, /* pGetFontData */
7952 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7953 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7954 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7955 NULL
, /* pGetICMProfile */
7956 NULL
, /* pGetImage */
7957 freetype_GetKerningPairs
, /* pGetKerningPairs */
7958 NULL
, /* pGetNearestColor */
7959 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7960 NULL
, /* pGetPixel */
7961 NULL
, /* pGetSystemPaletteEntries */
7962 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7963 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7964 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7965 freetype_GetTextFace
, /* pGetTextFace */
7966 freetype_GetTextMetrics
, /* pGetTextMetrics */
7967 NULL
, /* pGradientFill */
7968 NULL
, /* pIntersectClipRect */
7969 NULL
, /* pInvertRgn */
7971 NULL
, /* pModifyWorldTransform */
7973 NULL
, /* pOffsetClipRgn */
7974 NULL
, /* pOffsetViewportOrg */
7975 NULL
, /* pOffsetWindowOrg */
7976 NULL
, /* pPaintRgn */
7979 NULL
, /* pPolyBezier */
7980 NULL
, /* pPolyBezierTo */
7981 NULL
, /* pPolyDraw */
7982 NULL
, /* pPolyPolygon */
7983 NULL
, /* pPolyPolyline */
7984 NULL
, /* pPolygon */
7985 NULL
, /* pPolyline */
7986 NULL
, /* pPolylineTo */
7987 NULL
, /* pPutImage */
7988 NULL
, /* pRealizeDefaultPalette */
7989 NULL
, /* pRealizePalette */
7990 NULL
, /* pRectangle */
7991 NULL
, /* pResetDC */
7992 NULL
, /* pRestoreDC */
7993 NULL
, /* pRoundRect */
7995 NULL
, /* pScaleViewportExt */
7996 NULL
, /* pScaleWindowExt */
7997 NULL
, /* pSelectBitmap */
7998 NULL
, /* pSelectBrush */
7999 NULL
, /* pSelectClipPath */
8000 freetype_SelectFont
, /* pSelectFont */
8001 NULL
, /* pSelectPalette */
8002 NULL
, /* pSelectPen */
8003 NULL
, /* pSetArcDirection */
8004 NULL
, /* pSetBkColor */
8005 NULL
, /* pSetBkMode */
8006 NULL
, /* pSetDCBrushColor */
8007 NULL
, /* pSetDCPenColor */
8008 NULL
, /* pSetDIBColorTable */
8009 NULL
, /* pSetDIBitsToDevice */
8010 NULL
, /* pSetDeviceClipping */
8011 NULL
, /* pSetDeviceGammaRamp */
8012 NULL
, /* pSetLayout */
8013 NULL
, /* pSetMapMode */
8014 NULL
, /* pSetMapperFlags */
8015 NULL
, /* pSetPixel */
8016 NULL
, /* pSetPolyFillMode */
8017 NULL
, /* pSetROP2 */
8018 NULL
, /* pSetRelAbs */
8019 NULL
, /* pSetStretchBltMode */
8020 NULL
, /* pSetTextAlign */
8021 NULL
, /* pSetTextCharacterExtra */
8022 NULL
, /* pSetTextColor */
8023 NULL
, /* pSetTextJustification */
8024 NULL
, /* pSetViewportExt */
8025 NULL
, /* pSetViewportOrg */
8026 NULL
, /* pSetWindowExt */
8027 NULL
, /* pSetWindowOrg */
8028 NULL
, /* pSetWorldTransform */
8029 NULL
, /* pStartDoc */
8030 NULL
, /* pStartPage */
8031 NULL
, /* pStretchBlt */
8032 NULL
, /* pStretchDIBits */
8033 NULL
, /* pStrokeAndFillPath */
8034 NULL
, /* pStrokePath */
8035 NULL
, /* pUnrealizePalette */
8036 NULL
, /* pWidenPath */
8037 NULL
, /* wine_get_wgl_driver */
8038 GDI_PRIORITY_FONT_DRV
/* priority */
8041 #else /* HAVE_FREETYPE */
8043 /*************************************************************************/
8045 BOOL
WineEngInit(void)
8050 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8052 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8056 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8058 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8062 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8064 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8068 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8069 LPCWSTR font_file
, LPCWSTR font_path
)
8075 /*************************************************************************
8076 * GetRasterizerCaps (GDI32.@)
8078 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8080 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8082 lprs
->nLanguageID
= 0;
8086 #endif /* HAVE_FREETYPE */