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
, BOOL
*vert
);
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')
603 GSUB_ScriptRecord ScriptRecord
[1];
609 } GSUB_LangSysRecord
;
614 GSUB_LangSysRecord LangSysRecord
[1];
618 WORD LookupOrder
; /* Reserved */
619 WORD ReqFeatureIndex
;
621 WORD FeatureIndex
[1];
627 } GSUB_FeatureRecord
;
631 GSUB_FeatureRecord FeatureRecord
[1];
635 WORD FeatureParams
; /* Reserved */
637 WORD LookupListIndex
[1];
656 } GSUB_CoverageFormat1
;
661 WORD StartCoverageIndex
;
667 GSUB_RangeRecord RangeRecord
[1];
668 } GSUB_CoverageFormat2
;
671 WORD SubstFormat
; /* = 1 */
674 } GSUB_SingleSubstFormat1
;
677 WORD SubstFormat
; /* = 2 */
681 }GSUB_SingleSubstFormat2
;
683 #ifdef HAVE_CARBON_CARBON_H
684 static char *find_cache_dir(void)
688 static char cached_path
[MAX_PATH
];
689 static const char *wine
= "/Wine", *fonts
= "/Fonts";
691 if(*cached_path
) return cached_path
;
693 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
696 WARN("can't create cached data folder\n");
699 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
702 WARN("can't create cached data path\n");
706 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
708 ERR("Could not create full path\n");
712 strcat(cached_path
, wine
);
714 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
716 WARN("Couldn't mkdir %s\n", cached_path
);
720 strcat(cached_path
, fonts
);
721 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
723 WARN("Couldn't mkdir %s\n", cached_path
);
730 /******************************************************************
733 * Extracts individual TrueType font files from a Mac suitcase font
734 * and saves them into the user's caches directory (see
736 * Returns a NULL terminated array of filenames.
738 * We do this because they are apps that try to read ttf files
739 * themselves and they don't like Mac suitcase files.
741 static char **expand_mac_font(const char *path
)
748 const char *filename
;
752 unsigned int size
, max_size
;
755 TRACE("path %s\n", path
);
757 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
760 WARN("failed to get ref\n");
764 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
767 TRACE("no data fork, so trying resource fork\n");
768 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
771 TRACE("unable to open resource fork\n");
778 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
781 CloseResFile(res_ref
);
785 out_dir
= find_cache_dir();
787 filename
= strrchr(path
, '/');
788 if(!filename
) filename
= path
;
791 /* output filename has the form out_dir/filename_%04x.ttf */
792 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
799 unsigned short *num_faces_ptr
, num_faces
, face
;
802 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
804 fond
= Get1IndResource(fond_res
, idx
);
806 TRACE("got fond resource %d\n", idx
);
809 fam_rec
= *(FamRec
**)fond
;
810 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
811 num_faces
= GET_BE_WORD(*num_faces_ptr
);
813 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
814 TRACE("num faces %04x\n", num_faces
);
815 for(face
= 0; face
< num_faces
; face
++, assoc
++)
818 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
819 unsigned short size
, font_id
;
822 size
= GET_BE_WORD(assoc
->fontSize
);
823 font_id
= GET_BE_WORD(assoc
->fontID
);
826 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
830 TRACE("trying to load sfnt id %04x\n", font_id
);
831 sfnt
= GetResource(sfnt_res
, font_id
);
834 TRACE("can't get sfnt resource %04x\n", font_id
);
838 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
843 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
845 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
846 if(fd
!= -1 || errno
== EEXIST
)
850 unsigned char *sfnt_data
;
853 sfnt_data
= *(unsigned char**)sfnt
;
854 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
858 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
861 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
863 ret
.array
[ret
.size
++] = output
;
867 WARN("unable to create %s\n", output
);
868 HeapFree(GetProcessHeap(), 0, output
);
871 ReleaseResource(sfnt
);
874 ReleaseResource(fond
);
877 CloseResFile(res_ref
);
882 #endif /* HAVE_CARBON_CARBON_H */
884 static inline BOOL
is_win9x(void)
886 return GetVersion() & 0x80000000;
889 This function builds an FT_Fixed from a double. It fails if the absolute
890 value of the float number is greater than 32768.
892 static inline FT_Fixed
FT_FixedFromFloat(double f
)
898 This function builds an FT_Fixed from a FIXED. It simply put f.value
899 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
901 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
903 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
906 static BOOL
is_hinting_enabled(void)
908 static int enabled
= -1;
912 /* Use the >= 2.2.0 function if available */
913 if (pFT_Get_TrueType_Engine_Type
)
915 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
916 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
918 #ifdef FT_DRIVER_HAS_HINTER
921 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
922 FT_Module mod
= pFT_Get_Module(library
, "truetype");
923 enabled
= (mod
&& FT_DRIVER_HAS_HINTER(mod
));
926 else enabled
= FALSE
;
927 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
932 static BOOL
is_subpixel_rendering_enabled( void )
934 #ifdef HAVE_FREETYPE_FTLCDFIL_H
935 static int enabled
= -1;
938 enabled
= (pFT_Library_SetLcdFilter
&&
939 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
940 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
949 static const struct list
*get_face_list_from_family(const Family
*family
)
951 if (!list_empty(&family
->faces
))
952 return &family
->faces
;
954 return family
->replacement
;
957 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
963 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
965 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
967 const struct list
*face_list
;
968 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
970 face_list
= get_face_list_from_family(family
);
971 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
975 file
= strrchrW(face
->file
, '/');
980 if(strcmpiW(file
, file_name
)) continue;
988 static Family
*find_family_from_name(const WCHAR
*name
)
992 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
994 if(!strcmpiW(family
->FamilyName
, name
))
1001 static Family
*find_family_from_any_name(const WCHAR
*name
)
1005 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1007 if(!strcmpiW(family
->FamilyName
, name
))
1009 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1016 static void DumpSubstList(void)
1020 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1022 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1023 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1024 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1026 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1027 debugstr_w(psub
->to
.name
));
1032 static LPWSTR
strdupW(LPCWSTR p
)
1035 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1036 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1037 memcpy(ret
, p
, len
);
1041 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1046 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1048 if(!strcmpiW(element
->from
.name
, from_name
) &&
1049 (element
->from
.charset
== from_charset
||
1050 element
->from
.charset
== -1))
1057 #define ADD_FONT_SUBST_FORCE 1
1059 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1061 FontSubst
*from_exist
, *to_exist
;
1063 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1065 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1067 list_remove(&from_exist
->entry
);
1068 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1069 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1070 HeapFree(GetProcessHeap(), 0, from_exist
);
1076 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1080 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1081 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1084 list_add_tail(subst_list
, &subst
->entry
);
1089 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1090 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1091 HeapFree(GetProcessHeap(), 0, subst
);
1095 static WCHAR
*towstr(UINT cp
, const char *str
)
1100 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1101 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1102 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1106 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1108 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1109 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1110 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1114 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1116 CHAR
*p
= strrchr(str
, ',');
1120 nc
->charset
= strtol(p
+1, NULL
, 10);
1123 nc
->name
= towstr(CP_ACP
, str
);
1126 static void LoadSubstList(void)
1130 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1134 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1135 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1136 &hkey
) == ERROR_SUCCESS
) {
1138 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1139 &valuelen
, &datalen
, NULL
, NULL
);
1141 valuelen
++; /* returned value doesn't include room for '\0' */
1142 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1143 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1147 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1148 &dlen
) == ERROR_SUCCESS
) {
1149 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1151 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1152 split_subst_info(&psub
->from
, value
);
1153 split_subst_info(&psub
->to
, data
);
1155 /* Win 2000 doesn't allow mapping between different charsets
1156 or mapping of DEFAULT_CHARSET */
1157 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1158 psub
->to
.charset
== DEFAULT_CHARSET
) {
1159 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1160 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1161 HeapFree(GetProcessHeap(), 0, psub
);
1163 add_font_subst(&font_subst_list
, psub
, 0);
1165 /* reset dlen and vlen */
1169 HeapFree(GetProcessHeap(), 0, data
);
1170 HeapFree(GetProcessHeap(), 0, value
);
1176 static const LANGID mac_langid_table
[] =
1178 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
1179 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
1180 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
1181 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
1182 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
1183 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
1184 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
1185 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
1186 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
1187 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
1188 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
1189 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
1190 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
1191 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
1192 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
1193 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
1194 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
1195 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
1196 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
1197 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1198 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
1199 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
1200 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
1201 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
1202 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
1203 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
1204 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
1205 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
1206 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
1207 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
1208 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
1209 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
1210 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
1211 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1212 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
1213 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
1214 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
1215 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
1216 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
1217 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
1218 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
1219 0, /* TT_MAC_LANGID_YIDDISH */
1220 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
1221 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
1222 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
1223 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
1224 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
1225 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
1226 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
1227 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
1228 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1229 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
1230 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
1231 0, /* TT_MAC_LANGID_MOLDAVIAN */
1232 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
1233 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
1234 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
1235 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
1236 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1237 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
1238 0, /* TT_MAC_LANGID_KURDISH */
1239 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
1240 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
1241 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
1242 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
1243 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
1244 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
1245 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
1246 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
1247 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
1248 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
1249 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
1250 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
1251 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
1252 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
1253 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
1254 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
1255 0, /* TT_MAC_LANGID_BURMESE */
1256 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
1257 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
1258 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
1259 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
1260 0, /* TT_MAC_LANGID_TAGALOG */
1261 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1262 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1263 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
1264 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
1265 0, /* TT_MAC_LANGID_GALLA */
1266 0, /* TT_MAC_LANGID_SOMALI */
1267 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
1268 0, /* TT_MAC_LANGID_RUANDA */
1269 0, /* TT_MAC_LANGID_RUNDI */
1270 0, /* TT_MAC_LANGID_CHEWA */
1271 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
1272 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
1273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1275 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
1276 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
1277 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
1278 0, /* TT_MAC_LANGID_LATIN */
1279 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
1280 0, /* TT_MAC_LANGID_GUARANI */
1281 0, /* TT_MAC_LANGID_AYMARA */
1282 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
1283 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
1284 0, /* TT_MAC_LANGID_DZONGKHA */
1285 0, /* TT_MAC_LANGID_JAVANESE */
1286 0, /* TT_MAC_LANGID_SUNDANESE */
1287 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
1288 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
1289 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
1290 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
1291 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1292 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
1293 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
1294 0, /* TT_MAC_LANGID_TONGAN */
1295 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1296 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
1297 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1300 static inline WORD
get_mac_code_page( const FT_SfntName
*name
)
1302 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
1303 return 10000 + name
->encoding_id
;
1306 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
1311 switch (name
->platform_id
)
1313 case TT_PLATFORM_MICROSOFT
:
1314 res
+= 5; /* prefer the Microsoft name */
1315 switch (name
->encoding_id
)
1317 case TT_MS_ID_UNICODE_CS
:
1318 case TT_MS_ID_SYMBOL_CS
:
1319 name_lang
= name
->language_id
;
1325 case TT_PLATFORM_MACINTOSH
:
1326 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
1327 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1328 name_lang
= mac_langid_table
[name
->language_id
];
1330 case TT_PLATFORM_APPLE_UNICODE
:
1331 res
+= 2; /* prefer Unicode encodings */
1332 switch (name
->encoding_id
)
1334 case TT_APPLE_ID_DEFAULT
:
1335 case TT_APPLE_ID_ISO_10646
:
1336 case TT_APPLE_ID_UNICODE_2_0
:
1337 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1338 name_lang
= mac_langid_table
[name
->language_id
];
1347 if (name_lang
== lang
) res
+= 30;
1348 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
1349 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
1353 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
1359 switch (name
->platform_id
)
1361 case TT_PLATFORM_APPLE_UNICODE
:
1362 case TT_PLATFORM_MICROSOFT
:
1363 ret
= HeapAlloc( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
1364 for (i
= 0; i
< name
->string_len
/ 2; i
++)
1365 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
1368 case TT_PLATFORM_MACINTOSH
:
1369 codepage
= get_mac_code_page( name
);
1370 i
= MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, NULL
, 0 );
1371 ret
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(WCHAR
) );
1372 MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, ret
, i
);
1379 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
1382 FT_UInt num_names
, name_index
;
1383 int res
, best_lang
= 0, best_index
= -1;
1385 if (!FT_IS_SFNT(ft_face
)) return NULL
;
1387 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
1389 for (name_index
= 0; name_index
< num_names
; name_index
++)
1391 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
1392 if (name
.name_id
!= name_id
) continue;
1393 res
= match_name_table_language( &name
, language_id
);
1394 if (res
> best_lang
)
1397 best_index
= name_index
;
1401 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
1403 WCHAR
*ret
= copy_name_table_string( &name
);
1404 TRACE( "name %u found platform %u lang %04x %s\n",
1405 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
1411 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1413 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1414 if (f1
->scalable
) return TRUE
;
1415 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1416 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1419 static void release_family( Family
*family
)
1421 if (--family
->refcount
) return;
1422 assert( list_empty( &family
->faces
));
1423 list_remove( &family
->entry
);
1424 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1425 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1426 HeapFree( GetProcessHeap(), 0, family
);
1429 static void release_face( Face
*face
)
1431 if (--face
->refcount
) return;
1434 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1435 list_remove( &face
->entry
);
1436 release_family( face
->family
);
1438 HeapFree( GetProcessHeap(), 0, face
->file
);
1439 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1440 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1441 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1442 HeapFree( GetProcessHeap(), 0, face
);
1445 static inline int style_order(const Face
*face
)
1447 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1455 case NTM_BOLD
| NTM_ITALIC
:
1458 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1459 debugstr_w(face
->family
->FamilyName
),
1460 debugstr_w(face
->StyleName
),
1466 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1470 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1472 if (faces_equal( face
, cursor
))
1474 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1475 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1476 cursor
->font_version
, face
->font_version
);
1478 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1481 TRACE("Font %s already in list, refcount now %d\n",
1482 debugstr_w(face
->file
), cursor
->refcount
);
1485 if (face
->font_version
<= cursor
->font_version
)
1487 TRACE("Original font %s is newer so skipping %s\n",
1488 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1493 TRACE("Replacing original %s with %s\n",
1494 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1495 list_add_before( &cursor
->entry
, &face
->entry
);
1496 face
->family
= family
;
1499 release_face( cursor
);
1504 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1506 if (style_order( face
) < style_order( cursor
)) break;
1509 list_add_before( &cursor
->entry
, &face
->entry
);
1510 face
->family
= family
;
1516 /****************************************************************
1517 * NB This function stores the ptrs to the strings to save copying.
1518 * Don't free them after calling.
1520 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1522 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1523 family
->refcount
= 1;
1524 family
->FamilyName
= name
;
1525 family
->EnglishName
= english_name
;
1526 list_init( &family
->faces
);
1527 family
->replacement
= &family
->faces
;
1528 list_add_tail( &font_list
, &family
->entry
);
1533 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1535 DWORD type
, size
= sizeof(DWORD
);
1537 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1538 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1541 return ERROR_BAD_CONFIGURATION
;
1543 return ERROR_SUCCESS
;
1546 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1548 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1551 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1553 DWORD needed
, strike_index
= 0;
1556 /* If we have a File Name key then this is a real font, not just the parent
1557 key of a bunch of non-scalable strikes */
1558 needed
= buffer_size
;
1559 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1562 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1563 face
->cached_enum_data
= NULL
;
1564 face
->family
= NULL
;
1567 face
->file
= strdupW( buffer
);
1568 face
->StyleName
= strdupW(face_name
);
1570 needed
= buffer_size
;
1571 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1572 face
->FullName
= strdupW( buffer
);
1574 face
->FullName
= NULL
;
1576 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1577 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1578 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1579 reg_load_dword(hkey_face
, face_flags_value
, (DWORD
*)&face
->flags
);
1581 needed
= sizeof(face
->fs
);
1582 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1584 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1586 face
->scalable
= TRUE
;
1587 memset(&face
->size
, 0, sizeof(face
->size
));
1591 face
->scalable
= FALSE
;
1592 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1593 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1594 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1595 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1596 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1598 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1599 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1600 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1603 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1604 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1605 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1606 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1608 if (insert_face_in_family_list(face
, family
))
1609 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1611 release_face( face
);
1614 /* load bitmap strikes */
1616 needed
= buffer_size
;
1617 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1619 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1621 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1622 RegCloseKey(hkey_strike
);
1624 needed
= buffer_size
;
1628 /* move vertical fonts after their horizontal counterpart */
1629 /* assumes that font_list is already sorted by family name */
1630 static void reorder_vertical_fonts(void)
1632 Family
*family
, *next
, *vert_family
;
1633 struct list
*ptr
, *vptr
;
1634 struct list vertical_families
= LIST_INIT( vertical_families
);
1636 LIST_FOR_EACH_ENTRY_SAFE( family
, next
, &font_list
, Family
, entry
)
1638 if (family
->FamilyName
[0] != '@') continue;
1639 list_remove( &family
->entry
);
1640 list_add_tail( &vertical_families
, &family
->entry
);
1643 ptr
= list_head( &font_list
);
1644 vptr
= list_head( &vertical_families
);
1647 family
= LIST_ENTRY( ptr
, Family
, entry
);
1648 vert_family
= LIST_ENTRY( vptr
, Family
, entry
);
1649 if (strcmpiW( family
->FamilyName
, vert_family
->FamilyName
+ 1 ) > 0)
1651 list_remove( vptr
);
1652 list_add_before( ptr
, vptr
);
1653 vptr
= list_head( &vertical_families
);
1655 else ptr
= list_next( &font_list
, ptr
);
1657 list_move_tail( &font_list
, &vertical_families
);
1660 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1662 DWORD size
, family_index
= 0;
1667 size
= sizeof(buffer
);
1668 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1670 WCHAR
*english_family
= NULL
;
1671 WCHAR
*family_name
= strdupW( buffer
);
1672 DWORD face_index
= 0;
1674 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1675 TRACE("opened family key %s\n", debugstr_w(family_name
));
1676 size
= sizeof(buffer
);
1677 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1678 english_family
= strdupW( buffer
);
1680 family
= create_family(family_name
, english_family
);
1684 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1685 subst
->from
.name
= strdupW(english_family
);
1686 subst
->from
.charset
= -1;
1687 subst
->to
.name
= strdupW(family_name
);
1688 subst
->to
.charset
= -1;
1689 add_font_subst(&font_subst_list
, subst
, 0);
1692 size
= sizeof(buffer
);
1693 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1695 WCHAR
*face_name
= strdupW( buffer
);
1698 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1700 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1701 RegCloseKey(hkey_face
);
1703 HeapFree( GetProcessHeap(), 0, face_name
);
1704 size
= sizeof(buffer
);
1706 RegCloseKey(hkey_family
);
1707 release_family( family
);
1708 size
= sizeof(buffer
);
1711 reorder_vertical_fonts();
1714 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1717 HKEY hkey_wine_fonts
;
1719 /* We don't want to create the fonts key as volatile, so open this first */
1720 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1721 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1722 if(ret
!= ERROR_SUCCESS
)
1724 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1728 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1729 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1730 RegCloseKey(hkey_wine_fonts
);
1734 static void add_face_to_cache(Face
*face
)
1736 HKEY hkey_family
, hkey_face
;
1737 WCHAR
*face_key_name
;
1739 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1740 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1741 if(face
->family
->EnglishName
)
1742 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1743 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1746 face_key_name
= face
->StyleName
;
1749 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1750 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1751 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1753 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1756 HeapFree(GetProcessHeap(), 0, face_key_name
);
1758 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1759 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1761 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1762 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1764 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1765 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1766 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1767 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1769 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1773 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1774 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1775 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1776 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1777 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1778 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1780 RegCloseKey(hkey_face
);
1781 RegCloseKey(hkey_family
);
1784 static void remove_face_from_cache( Face
*face
)
1788 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1792 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1796 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1797 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1798 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1799 RegDeleteKeyW( hkey_family
, face_key_name
);
1800 HeapFree(GetProcessHeap(), 0, face_key_name
);
1802 RegCloseKey(hkey_family
);
1805 static WCHAR
*prepend_at(WCHAR
*family
)
1812 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1814 strcpyW(str
+ 1, family
);
1815 HeapFree(GetProcessHeap(), 0, family
);
1819 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1821 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
) );
1822 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1824 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1830 else if (!strcmpiW( *name
, *english
))
1832 HeapFree( GetProcessHeap(), 0, *english
);
1838 *name
= prepend_at( *name
);
1839 *english
= prepend_at( *english
);
1843 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1846 WCHAR
*name
, *english_name
;
1848 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1850 family
= find_family_from_name( name
);
1854 family
= create_family( name
, english_name
);
1857 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1858 subst
->from
.name
= strdupW( english_name
);
1859 subst
->from
.charset
= -1;
1860 subst
->to
.name
= strdupW( name
);
1861 subst
->to
.charset
= -1;
1862 add_font_subst( &font_subst_list
, subst
, 0 );
1867 HeapFree( GetProcessHeap(), 0, name
);
1868 HeapFree( GetProcessHeap(), 0, english_name
);
1875 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1877 FT_Fixed version
= 0;
1880 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1881 if (header
) version
= header
->Font_Revision
;
1886 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1889 FT_ULong table_size
= 0;
1891 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1892 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1893 if (flags
== 0) flags
= NTM_REGULAR
;
1895 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1896 flags
|= NTM_PS_OPENTYPE
;
1901 static inline void get_bitmap_size( FT_Face ft_face
, Bitmap_Size
*face_size
)
1903 My_FT_Bitmap_Size
*size
;
1904 FT_WinFNT_HeaderRec winfnt_header
;
1906 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1907 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1908 size
->height
, size
->width
, size
->size
>> 6,
1909 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1910 face_size
->height
= size
->height
;
1911 face_size
->width
= size
->width
;
1912 face_size
->size
= size
->size
;
1913 face_size
->x_ppem
= size
->x_ppem
;
1914 face_size
->y_ppem
= size
->y_ppem
;
1916 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
1917 face_size
->internal_leading
= winfnt_header
.internal_leading
;
1918 if (winfnt_header
.external_leading
> 0 &&
1919 (face_size
->height
==
1920 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
1921 face_size
->height
= winfnt_header
.pixel_height
;
1925 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1930 FT_WinFNT_HeaderRec winfnt_header
;
1933 memset( fs
, 0, sizeof(*fs
) );
1935 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1938 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1939 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1940 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1941 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1943 if (os2
->version
== 0)
1945 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1946 fs
->fsCsb
[0] = FS_LATIN1
;
1948 fs
->fsCsb
[0] = FS_SYMBOL
;
1952 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1953 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1958 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1960 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1961 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1962 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1967 if (fs
->fsCsb
[0] == 0)
1969 /* let's see if we can find any interesting cmaps */
1970 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1972 switch (ft_face
->charmaps
[i
]->encoding
)
1974 case FT_ENCODING_UNICODE
:
1975 case FT_ENCODING_APPLE_ROMAN
:
1976 fs
->fsCsb
[0] |= FS_LATIN1
;
1978 case FT_ENCODING_MS_SYMBOL
:
1979 fs
->fsCsb
[0] |= FS_SYMBOL
;
1988 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1992 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1995 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1996 if (!face
->StyleName
) face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1998 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1999 if (flags
& ADDFONT_VERTICAL_FONT
)
2000 face
->FullName
= prepend_at( face
->FullName
);
2006 face
->file
= towstr( CP_UNIXCP
, file
);
2007 face
->font_data_ptr
= NULL
;
2008 face
->font_data_size
= 0;
2009 if (!stat( file
, &st
))
2011 face
->dev
= st
.st_dev
;
2012 face
->ino
= st
.st_ino
;
2018 face
->font_data_ptr
= font_data_ptr
;
2019 face
->font_data_size
= font_data_size
;
2022 face
->face_index
= face_index
;
2023 get_fontsig( ft_face
, &face
->fs
);
2024 face
->ntmFlags
= get_ntm_flags( ft_face
);
2025 face
->font_version
= get_font_version( ft_face
);
2027 if (FT_IS_SCALABLE( ft_face
))
2029 memset( &face
->size
, 0, sizeof(face
->size
) );
2030 face
->scalable
= TRUE
;
2034 get_bitmap_size( ft_face
, &face
->size
);
2035 face
->scalable
= FALSE
;
2038 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
2039 face
->flags
= flags
;
2040 face
->family
= NULL
;
2041 face
->cached_enum_data
= NULL
;
2043 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2044 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
2045 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
2046 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
2051 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2052 FT_Long face_index
, DWORD flags
)
2057 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
2058 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
2059 if (insert_face_in_family_list( face
, family
))
2061 if (flags
& ADDFONT_ADD_TO_CACHE
)
2062 add_face_to_cache( face
);
2064 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
2065 debugstr_w(face
->StyleName
));
2067 release_face( face
);
2068 release_family( family
);
2071 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2072 FT_Long face_index
, BOOL allow_bitmap
)
2080 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
2081 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
2085 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
2086 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
2091 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
2095 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2096 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
2098 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2102 if (!FT_IS_SFNT( ft_face
))
2104 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
2106 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2112 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
2113 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
2114 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
2116 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2117 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
2121 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2122 we don't want to load these. */
2123 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
2127 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
2129 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
2135 if (!ft_face
->family_name
|| !ft_face
->style_name
)
2137 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
2143 pFT_Done_Face( ft_face
);
2147 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
2150 FT_Long face_index
= 0, num_faces
;
2153 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2154 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
2156 #ifdef HAVE_CARBON_CARBON_H
2159 char **mac_list
= expand_mac_font(file
);
2162 BOOL had_one
= FALSE
;
2164 for(cursor
= mac_list
; *cursor
; cursor
++)
2167 AddFontToList(*cursor
, NULL
, 0, flags
);
2168 HeapFree(GetProcessHeap(), 0, *cursor
);
2170 HeapFree(GetProcessHeap(), 0, mac_list
);
2175 #endif /* HAVE_CARBON_CARBON_H */
2178 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
2179 if (!ft_face
) return 0;
2181 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
2183 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
2184 pFT_Done_Face(ft_face
);
2188 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
2191 if (FT_HAS_VERTICAL(ft_face
))
2193 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
2194 flags
| ADDFONT_VERTICAL_FONT
);
2198 num_faces
= ft_face
->num_faces
;
2199 pFT_Done_Face(ft_face
);
2200 } while(num_faces
> ++face_index
);
2204 static int remove_font_resource( const char *file
, DWORD flags
)
2206 Family
*family
, *family_next
;
2207 Face
*face
, *face_next
;
2211 if (stat( file
, &st
) == -1) return 0;
2212 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2215 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2217 if (!face
->file
) continue;
2218 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2219 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2221 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2222 release_face( face
);
2226 release_family( family
);
2231 static void DumpFontList(void)
2236 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2237 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2238 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2239 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2241 TRACE(" %d", face
->size
.height
);
2248 /***********************************************************
2249 * The replacement list is a way to map an entire font
2250 * family onto another family. For example adding
2252 * [HKCU\Software\Wine\Fonts\Replacements]
2253 * "Wingdings"="Winedings"
2255 * would enumerate the Winedings font both as Winedings and
2256 * Wingdings. However if a real Wingdings font is present the
2257 * replacement does not take place.
2260 static void LoadReplaceList(void)
2263 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2267 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2268 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2270 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2271 &valuelen
, &datalen
, NULL
, NULL
);
2273 valuelen
++; /* returned value doesn't include room for '\0' */
2274 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2275 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2279 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2280 &dlen
) == ERROR_SUCCESS
) {
2281 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2282 /* "NewName"="Oldname" */
2283 if(!find_family_from_any_name(value
))
2285 Family
* const family
= find_family_from_any_name(data
);
2288 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2289 if (new_family
!= NULL
)
2291 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2292 new_family
->FamilyName
= strdupW(value
);
2293 new_family
->EnglishName
= NULL
;
2294 list_init(&new_family
->faces
);
2295 new_family
->replacement
= &family
->faces
;
2296 list_add_tail(&font_list
, &new_family
->entry
);
2301 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2306 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2308 /* reset dlen and vlen */
2312 HeapFree(GetProcessHeap(), 0, data
);
2313 HeapFree(GetProcessHeap(), 0, value
);
2318 static const WCHAR
*font_links_list
[] =
2320 Lucida_Sans_Unicode
,
2321 Microsoft_Sans_Serif
,
2325 static const struct font_links_defaults_list
2327 /* Keyed off substitution for "MS Shell Dlg" */
2328 const WCHAR
*shelldlg
;
2329 /* Maximum of four substitutes, plus terminating NULL pointer */
2330 const WCHAR
*substitutes
[5];
2331 } font_links_defaults_list
[] =
2333 /* Non East-Asian */
2334 { Tahoma
, /* FIXME unverified ordering */
2335 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2337 /* Below lists are courtesy of
2338 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2342 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2344 /* Chinese Simplified */
2346 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2350 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2352 /* Chinese Traditional */
2354 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2359 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2361 SYSTEM_LINKS
*font_link
;
2363 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2365 if(!strcmpiW(font_link
->font_name
, name
))
2372 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2383 SYSTEM_LINKS
*font_link
;
2385 psub
= get_font_subst(&font_subst_list
, name
, -1);
2386 /* Don't store fonts that are only substitutes for other fonts */
2389 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2393 font_link
= find_font_link(name
);
2394 if (font_link
== NULL
)
2396 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2397 font_link
->font_name
= strdupW(name
);
2398 list_init(&font_link
->links
);
2399 list_add_tail(&system_links
, &font_link
->entry
);
2402 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2403 for (i
= 0; values
[i
] != NULL
; i
++)
2405 const struct list
*face_list
;
2406 CHILD_FONT
*child_font
;
2409 if (!strcmpiW(name
,value
))
2411 psub
= get_font_subst(&font_subst_list
, value
, -1);
2413 value
= psub
->to
.name
;
2414 family
= find_family_from_name(value
);
2418 /* Use first extant filename for this Family */
2419 face_list
= get_face_list_from_family(family
);
2420 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2424 file
= strrchrW(face
->file
, '/');
2433 face
= find_face_from_filename(file
, value
);
2436 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2440 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2441 child_font
->face
= face
;
2442 child_font
->font
= NULL
;
2443 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2444 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2445 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2446 child_font
->face
->face_index
);
2447 list_add_tail(&font_link
->links
, &child_font
->entry
);
2449 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2455 /*************************************************************
2458 static BOOL
init_system_links(void)
2462 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2463 WCHAR
*value
, *data
;
2464 WCHAR
*entry
, *next
;
2465 SYSTEM_LINKS
*font_link
, *system_font_link
;
2466 CHILD_FONT
*child_font
;
2467 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2468 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2469 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2474 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2476 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2477 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2478 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2479 val_len
= max_val
+ 1;
2480 data_len
= max_data
;
2482 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2484 psub
= get_font_subst(&font_subst_list
, value
, -1);
2485 /* Don't store fonts that are only substitutes for other fonts */
2488 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2491 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2492 font_link
->font_name
= strdupW(value
);
2493 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2494 list_init(&font_link
->links
);
2495 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2498 CHILD_FONT
*child_font
;
2500 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2502 next
= entry
+ strlenW(entry
) + 1;
2504 face_name
= strchrW(entry
, ',');
2508 while(isspaceW(*face_name
))
2511 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2513 face_name
= psub
->to
.name
;
2515 face
= find_face_from_filename(entry
, face_name
);
2518 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2522 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2523 child_font
->face
= face
;
2524 child_font
->font
= NULL
;
2525 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2526 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2527 TRACE("Adding file %s index %ld\n",
2528 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2529 list_add_tail(&font_link
->links
, &child_font
->entry
);
2531 list_add_tail(&system_links
, &font_link
->entry
);
2533 val_len
= max_val
+ 1;
2534 data_len
= max_data
;
2537 HeapFree(GetProcessHeap(), 0, value
);
2538 HeapFree(GetProcessHeap(), 0, data
);
2543 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2545 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2549 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2551 const FontSubst
*psub2
;
2552 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2554 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2556 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2557 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2559 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2560 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2562 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2564 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2570 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2573 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2574 system_font_link
->font_name
= strdupW(System
);
2575 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2576 list_init(&system_font_link
->links
);
2578 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2581 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2582 child_font
->face
= face
;
2583 child_font
->font
= NULL
;
2584 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2585 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2586 TRACE("Found Tahoma in %s index %ld\n",
2587 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2588 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2590 font_link
= find_font_link(Tahoma
);
2591 if (font_link
!= NULL
)
2593 CHILD_FONT
*font_link_entry
;
2594 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2596 CHILD_FONT
*new_child
;
2597 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2598 new_child
->face
= font_link_entry
->face
;
2599 new_child
->font
= NULL
;
2600 new_child
->face
->refcount
++;
2601 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2602 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2603 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2606 list_add_tail(&system_links
, &system_font_link
->entry
);
2610 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2613 struct dirent
*dent
;
2614 char path
[MAX_PATH
];
2616 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2618 dir
= opendir(dirname
);
2620 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2623 while((dent
= readdir(dir
)) != NULL
) {
2624 struct stat statbuf
;
2626 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2629 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2631 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2633 if(stat(path
, &statbuf
) == -1)
2635 WARN("Can't stat %s\n", debugstr_a(path
));
2638 if(S_ISDIR(statbuf
.st_mode
))
2639 ReadFontDir(path
, external_fonts
);
2642 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2643 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2644 AddFontToList(path
, NULL
, 0, addfont_flags
);
2651 #ifdef SONAME_LIBFONTCONFIG
2653 static BOOL fontconfig_enabled
;
2655 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2661 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2662 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2664 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2668 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2669 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2670 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2671 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2672 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2678 static void init_fontconfig(void)
2680 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2684 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2688 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2689 LOAD_FUNCPTR(FcConfigSubstitute
);
2690 LOAD_FUNCPTR(FcFontList
);
2691 LOAD_FUNCPTR(FcFontSetDestroy
);
2692 LOAD_FUNCPTR(FcInit
);
2693 LOAD_FUNCPTR(FcObjectSetAdd
);
2694 LOAD_FUNCPTR(FcObjectSetCreate
);
2695 LOAD_FUNCPTR(FcObjectSetDestroy
);
2696 LOAD_FUNCPTR(FcPatternCreate
);
2697 LOAD_FUNCPTR(FcPatternDestroy
);
2698 LOAD_FUNCPTR(FcPatternGetBool
);
2699 LOAD_FUNCPTR(FcPatternGetInteger
);
2700 LOAD_FUNCPTR(FcPatternGetString
);
2705 FcPattern
*pattern
= pFcPatternCreate();
2706 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2707 default_aa_flags
= parse_aa_pattern( pattern
);
2708 pFcPatternDestroy( pattern
);
2709 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2710 fontconfig_enabled
= TRUE
;
2714 static void load_fontconfig_fonts(void)
2723 if (!fontconfig_enabled
) return;
2725 pat
= pFcPatternCreate();
2726 os
= pFcObjectSetCreate();
2727 pFcObjectSetAdd(os
, FC_FILE
);
2728 pFcObjectSetAdd(os
, FC_SCALABLE
);
2729 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2730 pFcObjectSetAdd(os
, FC_RGBA
);
2731 fontset
= pFcFontList(NULL
, pat
, os
);
2732 if(!fontset
) return;
2733 for(i
= 0; i
< fontset
->nfont
; i
++) {
2737 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2740 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2742 /* We're just interested in OT/TT fonts for now, so this hack just
2743 picks up the scalable fonts without extensions .pf[ab] to save time
2744 loading every other font */
2746 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2748 TRACE("not scalable\n");
2752 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2753 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2755 len
= strlen( file
);
2756 if(len
< 4) continue;
2757 ext
= &file
[ len
- 3 ];
2758 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2759 AddFontToList(file
, NULL
, 0,
2760 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2762 pFcFontSetDestroy(fontset
);
2763 pFcObjectSetDestroy(os
);
2764 pFcPatternDestroy(pat
);
2767 #elif defined(HAVE_CARBON_CARBON_H)
2769 static void load_mac_font_callback(const void *value
, void *context
)
2771 CFStringRef pathStr
= value
;
2775 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2776 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2777 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2779 TRACE("font file %s\n", path
);
2780 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2782 HeapFree(GetProcessHeap(), 0, path
);
2785 static void load_mac_fonts(void)
2787 CFStringRef removeDupesKey
;
2788 CFBooleanRef removeDupesValue
;
2789 CFDictionaryRef options
;
2790 CTFontCollectionRef col
;
2792 CFMutableSetRef paths
;
2795 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2796 removeDupesValue
= kCFBooleanTrue
;
2797 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2798 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2799 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2800 if (options
) CFRelease(options
);
2803 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2807 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2811 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2815 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2818 WARN("CFSetCreateMutable failed\n");
2823 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2825 CTFontDescriptorRef desc
;
2834 desc
= CFArrayGetValueAtIndex(descs
, i
);
2836 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2837 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2838 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2839 if (!font
) continue;
2841 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2848 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2850 if (status
!= noErr
) continue;
2852 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2855 ext
= CFURLCopyPathExtension(url
);
2858 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2859 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2868 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2870 if (!path
) continue;
2872 CFSetAddValue(paths
, path
);
2878 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2884 static char *get_data_dir_path( LPCWSTR file
)
2886 char *unix_name
= NULL
;
2887 const char *data_dir
= wine_get_data_dir();
2889 if (!data_dir
) data_dir
= wine_get_build_dir();
2893 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2895 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2896 strcpy(unix_name
, data_dir
);
2897 strcat(unix_name
, "/fonts/");
2899 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2904 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2907 char *unix_name
= get_data_dir_path( file
);
2911 EnterCriticalSection( &freetype_cs
);
2912 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2913 LeaveCriticalSection( &freetype_cs
);
2914 HeapFree(GetProcessHeap(), 0, unix_name
);
2919 static char *get_winfonts_dir_path(LPCWSTR file
)
2921 static const WCHAR slashW
[] = {'\\','\0'};
2922 WCHAR windowsdir
[MAX_PATH
];
2924 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2925 strcatW(windowsdir
, fontsW
);
2926 strcatW(windowsdir
, slashW
);
2927 strcatW(windowsdir
, file
);
2928 return wine_get_unix_file_name( windowsdir
);
2931 static void load_system_fonts(void)
2934 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2935 const WCHAR
* const *value
;
2937 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2940 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2941 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2942 strcatW(windowsdir
, fontsW
);
2943 for(value
= SystemFontValues
; *value
; value
++) {
2944 dlen
= sizeof(data
);
2945 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2949 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2950 if((unixname
= wine_get_unix_file_name(pathW
))) {
2951 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2952 HeapFree(GetProcessHeap(), 0, unixname
);
2955 load_font_from_data_dir(data
);
2962 /*************************************************************
2964 * This adds registry entries for any externally loaded fonts
2965 * (fonts from fontconfig or FontDirs). It also deletes entries
2966 * of no longer existing fonts.
2969 static void update_reg_entries(void)
2971 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2977 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2979 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2980 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2981 ERR("Can't create Windows font reg key\n");
2985 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2986 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2987 ERR("Can't create Windows font reg key\n");
2991 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2992 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2993 ERR("Can't create external font reg key\n");
2997 /* enumerate the fonts and add external ones to the two keys */
2999 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
3000 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
3002 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
3006 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3007 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3008 strcpyW(valueW
, face
->FullName
);
3012 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3013 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3014 strcpyW(valueW
, family
->FamilyName
);
3017 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
3018 path
= wine_get_dos_file_name( buffer
);
3019 HeapFree( GetProcessHeap(), 0, buffer
);
3023 else if ((file
= strrchrW(face
->file
, '/')))
3028 len
= strlenW(file
) + 1;
3029 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3030 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3031 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3033 HeapFree(GetProcessHeap(), 0, path
);
3034 HeapFree(GetProcessHeap(), 0, valueW
);
3038 if(external_key
) RegCloseKey(external_key
);
3039 if(win9x_key
) RegCloseKey(win9x_key
);
3040 if(winnt_key
) RegCloseKey(winnt_key
);
3044 static void delete_external_font_keys(void)
3046 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3047 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
3051 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3052 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3053 ERR("Can't create Windows font reg key\n");
3057 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3058 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3059 ERR("Can't create Windows font reg key\n");
3063 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
3064 ERR("Can't create external font reg key\n");
3068 /* Delete all external fonts added last time */
3070 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3071 &valuelen
, &datalen
, NULL
, NULL
);
3072 valuelen
++; /* returned value doesn't include room for '\0' */
3073 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3074 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3076 dlen
= datalen
* sizeof(WCHAR
);
3079 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
3080 &dlen
) == ERROR_SUCCESS
) {
3082 RegDeleteValueW(winnt_key
, valueW
);
3083 RegDeleteValueW(win9x_key
, valueW
);
3084 /* reset dlen and vlen */
3088 HeapFree(GetProcessHeap(), 0, data
);
3089 HeapFree(GetProcessHeap(), 0, valueW
);
3091 /* Delete the old external fonts key */
3092 RegCloseKey(external_key
);
3093 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
3096 if(win9x_key
) RegCloseKey(win9x_key
);
3097 if(winnt_key
) RegCloseKey(winnt_key
);
3100 /*************************************************************
3101 * WineEngAddFontResourceEx
3104 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3110 if (ft_handle
) /* do it only if we have freetype up and running */
3114 EnterCriticalSection( &freetype_cs
);
3116 if((unixname
= wine_get_unix_file_name(file
)))
3118 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3120 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3121 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
3122 HeapFree(GetProcessHeap(), 0, unixname
);
3124 if (!ret
&& !strchrW(file
, '\\')) {
3125 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3126 if ((unixname
= get_winfonts_dir_path( file
)))
3128 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3129 HeapFree(GetProcessHeap(), 0, unixname
);
3131 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3132 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3134 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3135 HeapFree(GetProcessHeap(), 0, unixname
);
3139 LeaveCriticalSection( &freetype_cs
);
3144 /*************************************************************
3145 * WineEngAddFontMemResourceEx
3148 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3152 if (ft_handle
) /* do it only if we have freetype up and running */
3154 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
3156 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
3157 memcpy(pFontCopy
, pbFont
, cbFont
);
3159 EnterCriticalSection( &freetype_cs
);
3160 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3161 LeaveCriticalSection( &freetype_cs
);
3165 TRACE("AddFontToList failed\n");
3166 HeapFree(GetProcessHeap(), 0, pFontCopy
);
3169 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3170 * For now return something unique but quite random
3172 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
3173 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
3180 /*************************************************************
3181 * WineEngRemoveFontResourceEx
3184 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3190 if (ft_handle
) /* do it only if we have freetype up and running */
3194 EnterCriticalSection( &freetype_cs
);
3196 if ((unixname
= wine_get_unix_file_name(file
)))
3198 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3200 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3201 ret
= remove_font_resource( unixname
, addfont_flags
);
3202 HeapFree(GetProcessHeap(), 0, unixname
);
3204 if (!ret
&& !strchrW(file
, '\\'))
3206 if ((unixname
= get_winfonts_dir_path( file
)))
3208 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3209 HeapFree(GetProcessHeap(), 0, unixname
);
3211 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3213 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3214 HeapFree(GetProcessHeap(), 0, unixname
);
3218 LeaveCriticalSection( &freetype_cs
);
3223 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3229 if (!font_file
) return NULL
;
3231 file_len
= strlenW( font_file
);
3233 if (font_path
&& font_path
[0])
3235 int path_len
= strlenW( font_path
);
3236 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3237 if (!fullname
) return NULL
;
3238 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3239 fullname
[path_len
] = '\\';
3240 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3244 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3245 if (!len
) return NULL
;
3246 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3247 if (!fullname
) return NULL
;
3248 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3251 unix_name
= wine_get_unix_file_name( fullname
);
3252 HeapFree( GetProcessHeap(), 0, fullname
);
3256 #include <pshpack1.h>
3259 WORD num_of_resources
;
3263 CHAR dfCopyright
[60];
3269 WORD dfInternalLeading
;
3270 WORD dfExternalLeading
;
3278 BYTE dfPitchAndFamily
;
3289 CHAR szFaceName
[LF_FACESIZE
];
3292 #include <poppack.h>
3294 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3295 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3297 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3299 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3301 WCHAR
*name
, *english_name
;
3303 NEWTEXTMETRICEXW ntm
;
3306 if (!ft_face
) return FALSE
;
3307 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3308 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3309 pFT_Done_Face( ft_face
);
3311 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3312 release_face( face
);
3313 HeapFree( GetProcessHeap(), 0, name
);
3314 HeapFree( GetProcessHeap(), 0, english_name
);
3316 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3318 memset( fd
, 0, sizeof(*fd
) );
3320 fd
->num_of_resources
= 1;
3322 fd
->dfVersion
= 0x200;
3323 fd
->dfSize
= sizeof(*fd
);
3324 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3325 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3326 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3328 fd
->dfHorizRes
= 72;
3329 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3330 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3331 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3332 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3333 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3334 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3335 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3336 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3338 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3339 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3340 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3341 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3342 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3343 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3344 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3345 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3346 fd
->dfWidthBytes
= 0;
3348 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3350 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3355 #define NE_FFLAGS_LIBMODULE 0x8000
3356 #define NE_OSFLAGS_WINDOWS 0x02
3358 static const char dos_string
[0x40] = "This is a TrueType resource file";
3359 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3361 #include <pshpack2.h>
3382 struct ne_typeinfo fontdir_type
;
3383 struct ne_nameinfo fontdir_name
;
3384 struct ne_typeinfo scalable_type
;
3385 struct ne_nameinfo scalable_name
;
3387 BYTE fontdir_res_name
[8];
3390 #include <poppack.h>
3392 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3396 DWORD size
, written
;
3398 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3399 char *font_fileA
, *last_part
, *ext
;
3400 IMAGE_DOS_HEADER dos
;
3401 IMAGE_OS2_HEADER ne
=
3403 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3405 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3406 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3408 struct rsrc_tab rsrc_tab
=
3412 { 0, 0, 0x0c50, 0x2c, 0 },
3414 { 0, 0, 0x0c50, 0x8001, 0 },
3416 { 7,'F','O','N','T','D','I','R'}
3419 memset( &dos
, 0, sizeof(dos
) );
3420 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3421 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3423 /* import name is last part\0, resident name is last part without extension
3424 non-resident name is "FONTRES:" + lfFaceName */
3426 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3427 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3428 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3430 last_part
= strrchr( font_fileA
, '\\' );
3431 if (last_part
) last_part
++;
3432 else last_part
= font_fileA
;
3433 import_name_len
= strlen( last_part
) + 1;
3435 ext
= strchr( last_part
, '.' );
3436 if (ext
) res_name_len
= ext
- last_part
;
3437 else res_name_len
= import_name_len
- 1;
3439 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3441 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3442 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3443 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3444 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3446 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3448 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3449 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3450 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3451 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3453 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3454 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3458 HeapFree( GetProcessHeap(), 0, font_fileA
);
3462 memcpy( ptr
, &dos
, sizeof(dos
) );
3463 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3464 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3466 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3467 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3469 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3470 *ptr
++ = res_name_len
;
3471 memcpy( ptr
, last_part
, res_name_len
);
3473 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3474 *ptr
++ = import_name_len
;
3475 memcpy( ptr
, last_part
, import_name_len
);
3477 ptr
= start
+ ne
.ne_nrestab
;
3478 *ptr
++ = non_res_name_len
;
3479 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3480 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3482 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3483 memcpy( ptr
, font_fileA
, font_file_len
);
3485 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3486 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3488 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3489 if (file
!= INVALID_HANDLE_VALUE
)
3491 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3493 CloseHandle( file
);
3496 HeapFree( GetProcessHeap(), 0, start
);
3497 HeapFree( GetProcessHeap(), 0, font_fileA
);
3502 /*************************************************************
3503 * WineEngCreateScalableFontResource
3506 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3507 LPCWSTR font_file
, LPCWSTR font_path
)
3509 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3510 struct fontdir fontdir
;
3513 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3514 SetLastError( ERROR_INVALID_PARAMETER
);
3517 if (hidden
) fontdir
.dfType
|= 0x80;
3518 ret
= create_fot( resource
, font_file
, &fontdir
);
3521 HeapFree( GetProcessHeap(), 0, unix_name
);
3525 static const struct nls_update_font_list
3527 UINT ansi_cp
, oem_cp
;
3528 const char *oem
, *fixed
, *system
;
3529 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3530 /* these are for font substitutes */
3531 const char *shelldlg
, *tmsrmn
;
3532 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3536 const char *from
, *to
;
3537 } arial_0
, courier_new_0
, times_new_roman_0
;
3538 } nls_update_font_list
[] =
3540 /* Latin 1 (United States) */
3541 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3542 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3543 "Tahoma","Times New Roman",
3544 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3547 /* Latin 1 (Multilingual) */
3548 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3549 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3550 "Tahoma","Times New Roman", /* FIXME unverified */
3551 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3554 /* Eastern Europe */
3555 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3556 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3557 "Tahoma","Times New Roman", /* FIXME unverified */
3558 "Fixedsys,238", "System,238",
3559 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3560 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3561 { "Arial CE,0", "Arial,238" },
3562 { "Courier New CE,0", "Courier New,238" },
3563 { "Times New Roman CE,0", "Times New Roman,238" }
3566 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3567 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3568 "Tahoma","Times New Roman", /* FIXME unverified */
3569 "Fixedsys,204", "System,204",
3570 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3571 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3572 { "Arial Cyr,0", "Arial,204" },
3573 { "Courier New Cyr,0", "Courier New,204" },
3574 { "Times New Roman Cyr,0", "Times New Roman,204" }
3577 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3578 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3579 "Tahoma","Times New Roman", /* FIXME unverified */
3580 "Fixedsys,161", "System,161",
3581 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3582 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3583 { "Arial Greek,0", "Arial,161" },
3584 { "Courier New Greek,0", "Courier New,161" },
3585 { "Times New Roman Greek,0", "Times New Roman,161" }
3588 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3589 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3590 "Tahoma","Times New Roman", /* FIXME unverified */
3591 "Fixedsys,162", "System,162",
3592 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3593 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3594 { "Arial Tur,0", "Arial,162" },
3595 { "Courier New Tur,0", "Courier New,162" },
3596 { "Times New Roman Tur,0", "Times New Roman,162" }
3599 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3600 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3601 "Tahoma","Times New Roman", /* FIXME unverified */
3602 "Fixedsys,177", "System,177",
3603 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3604 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3608 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3609 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3610 "Microsoft Sans Serif","Times New Roman",
3611 "Fixedsys,178", "System,178",
3612 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3613 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3617 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3618 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3619 "Tahoma","Times New Roman", /* FIXME unverified */
3620 "Fixedsys,186", "System,186",
3621 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3622 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3623 { "Arial Baltic,0", "Arial,186" },
3624 { "Courier New Baltic,0", "Courier New,186" },
3625 { "Times New Roman Baltic,0", "Times New Roman,186" }
3628 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3629 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3630 "Tahoma","Times New Roman", /* FIXME unverified */
3631 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3635 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3636 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3637 "Tahoma","Times New Roman", /* FIXME unverified */
3638 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3642 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3643 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3644 "MS UI Gothic","MS Serif",
3645 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3648 /* Chinese Simplified */
3649 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3650 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3651 "SimSun", "NSimSun",
3652 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3656 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3657 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3659 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3662 /* Chinese Traditional */
3663 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3664 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3665 "PMingLiU", "MingLiU",
3666 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3671 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3673 return ( ansi_cp
== 932 /* CP932 for Japanese */
3674 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3675 || ansi_cp
== 949 /* CP949 for Korean */
3676 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3679 static inline HKEY
create_fonts_NT_registry_key(void)
3683 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3684 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3688 static inline HKEY
create_fonts_9x_registry_key(void)
3692 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3693 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3697 static inline HKEY
create_config_fonts_registry_key(void)
3701 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3702 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3706 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3708 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3710 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3711 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3712 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3713 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3716 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3719 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3721 RegDeleteValueA(hkey
, name
);
3724 static void update_font_association_info(UINT current_ansi_codepage
)
3726 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3727 static const char *assoc_charset_subkey
= "Associated Charset";
3729 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3732 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3735 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3737 switch (current_ansi_codepage
)
3740 set_value_key(hsubkey
, "ANSI(00)", "NO");
3741 set_value_key(hsubkey
, "OEM(FF)", "NO");
3742 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3747 set_value_key(hsubkey
, "ANSI(00)", "YES");
3748 set_value_key(hsubkey
, "OEM(FF)", "YES");
3749 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3752 RegCloseKey(hsubkey
);
3755 /* TODO: Associated DefaultFonts */
3761 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3764 static void update_font_info(void)
3766 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3767 char buf
[40], cpbuf
[40];
3770 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3771 DWORD screen_dpi
= 96, font_dpi
= 0;
3774 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3775 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3776 &hkey
) == ERROR_SUCCESS
)
3778 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3782 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3785 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3787 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3788 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3789 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3790 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3791 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3793 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3794 if (is_dbcs_ansi_cp(ansi_cp
))
3795 use_default_fallback
= TRUE
;
3799 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3801 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3806 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3807 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3809 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3810 ansi_cp
, oem_cp
, screen_dpi
);
3812 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3813 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3816 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3820 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3821 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3823 hkey
= create_config_fonts_registry_key();
3824 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3825 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3826 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3829 hkey
= create_fonts_NT_registry_key();
3830 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3833 hkey
= create_fonts_9x_registry_key();
3834 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3837 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3839 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3840 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3841 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3842 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3844 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3845 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3846 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3847 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3848 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3849 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3850 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3851 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3853 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3854 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3855 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3863 /* Delete the FontSubstitutes from other locales */
3864 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3866 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3867 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3868 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3874 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3876 /* update locale dependent font association info in registry.
3877 update only when codepages changed, not logpixels. */
3878 if (strcmp(buf
, cpbuf
) != 0)
3879 update_font_association_info(ansi_cp
);
3882 static BOOL
init_freetype(void)
3884 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3887 "Wine cannot find the FreeType font library. To enable Wine to\n"
3888 "use TrueType fonts please install a version of FreeType greater than\n"
3889 "or equal to 2.0.5.\n"
3890 "http://www.freetype.org\n");
3894 #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;}
3896 LOAD_FUNCPTR(FT_Done_Face
)
3897 LOAD_FUNCPTR(FT_Get_Char_Index
)
3898 LOAD_FUNCPTR(FT_Get_First_Char
)
3899 LOAD_FUNCPTR(FT_Get_Module
)
3900 LOAD_FUNCPTR(FT_Get_Next_Char
)
3901 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3902 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3903 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3904 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3905 LOAD_FUNCPTR(FT_Init_FreeType
)
3906 LOAD_FUNCPTR(FT_Library_Version
)
3907 LOAD_FUNCPTR(FT_Load_Glyph
)
3908 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3909 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3910 #ifndef FT_MULFIX_INLINED
3911 LOAD_FUNCPTR(FT_MulFix
)
3913 LOAD_FUNCPTR(FT_New_Face
)
3914 LOAD_FUNCPTR(FT_New_Memory_Face
)
3915 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3916 LOAD_FUNCPTR(FT_Outline_Transform
)
3917 LOAD_FUNCPTR(FT_Outline_Translate
)
3918 LOAD_FUNCPTR(FT_Render_Glyph
)
3919 LOAD_FUNCPTR(FT_Select_Charmap
)
3920 LOAD_FUNCPTR(FT_Set_Charmap
)
3921 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3922 LOAD_FUNCPTR(FT_Vector_Transform
)
3923 LOAD_FUNCPTR(FT_Vector_Unit
)
3925 /* Don't warn if these ones are missing */
3926 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3927 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3928 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3931 if(pFT_Init_FreeType(&library
) != 0) {
3932 ERR("Can't init FreeType library\n");
3933 wine_dlclose(ft_handle
, NULL
, 0);
3937 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3939 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3940 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3941 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3942 ((FT_Version
.patch
) & 0x0000ff);
3944 font_driver
= &freetype_funcs
;
3949 "Wine cannot find certain functions that it needs inside the FreeType\n"
3950 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3951 "FreeType to at least version 2.1.4.\n"
3952 "http://www.freetype.org\n");
3953 wine_dlclose(ft_handle
, NULL
, 0);
3958 static void init_font_list(void)
3960 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3961 static const WCHAR pathW
[] = {'P','a','t','h',0};
3963 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3964 WCHAR windowsdir
[MAX_PATH
];
3966 const char *data_dir
;
3968 delete_external_font_keys();
3970 /* load the system bitmap fonts */
3971 load_system_fonts();
3973 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3974 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3975 strcatW(windowsdir
, fontsW
);
3976 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3978 ReadFontDir(unixname
, FALSE
);
3979 HeapFree(GetProcessHeap(), 0, unixname
);
3982 /* load the system truetype fonts */
3983 data_dir
= wine_get_data_dir();
3984 if (!data_dir
) data_dir
= wine_get_build_dir();
3985 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3987 strcpy(unixname
, data_dir
);
3988 strcat(unixname
, "/fonts/");
3989 ReadFontDir(unixname
, TRUE
);
3990 HeapFree(GetProcessHeap(), 0, unixname
);
3993 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3994 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3995 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3997 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3998 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3999 &hkey
) == ERROR_SUCCESS
)
4001 LPWSTR data
, valueW
;
4002 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4003 &valuelen
, &datalen
, NULL
, NULL
);
4005 valuelen
++; /* returned value doesn't include room for '\0' */
4006 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
4007 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
4010 dlen
= datalen
* sizeof(WCHAR
);
4012 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
4013 &dlen
) == ERROR_SUCCESS
)
4015 if(data
[0] && (data
[1] == ':'))
4017 if((unixname
= wine_get_unix_file_name(data
)))
4019 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4020 HeapFree(GetProcessHeap(), 0, unixname
);
4023 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
4025 WCHAR pathW
[MAX_PATH
];
4026 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
4029 sprintfW(pathW
, fmtW
, windowsdir
, data
);
4030 if((unixname
= wine_get_unix_file_name(pathW
)))
4032 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4033 HeapFree(GetProcessHeap(), 0, unixname
);
4036 load_font_from_data_dir(data
);
4038 /* reset dlen and vlen */
4043 HeapFree(GetProcessHeap(), 0, data
);
4044 HeapFree(GetProcessHeap(), 0, valueW
);
4048 #ifdef SONAME_LIBFONTCONFIG
4049 load_fontconfig_fonts();
4050 #elif defined(HAVE_CARBON_CARBON_H)
4054 /* then look in any directories that we've specified in the config file */
4055 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4056 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
4062 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
4064 len
+= sizeof(WCHAR
);
4065 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
4066 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
4068 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
4069 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
4070 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
4071 TRACE( "got font path %s\n", debugstr_a(valueA
) );
4076 LPSTR next
= strchr( ptr
, ':' );
4077 if (next
) *next
++ = 0;
4078 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
4079 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
4081 strcpy( unixname
, home
);
4082 strcat( unixname
, ptr
+ 1 );
4083 ReadFontDir( unixname
, TRUE
);
4084 HeapFree( GetProcessHeap(), 0, unixname
);
4087 ReadFontDir( ptr
, TRUE
);
4090 HeapFree( GetProcessHeap(), 0, valueA
);
4092 HeapFree( GetProcessHeap(), 0, valueW
);
4098 static BOOL
move_to_front(const WCHAR
*name
)
4100 Family
*family
, *cursor2
;
4101 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
4103 if(!strcmpiW(family
->FamilyName
, name
))
4105 list_remove(&family
->entry
);
4106 list_add_head(&font_list
, &family
->entry
);
4113 static BOOL
set_default(const WCHAR
**name_list
)
4117 if (move_to_front(*name_list
)) return TRUE
;
4124 static void reorder_font_list(void)
4126 set_default( default_serif_list
);
4127 set_default( default_fixed_list
);
4128 set_default( default_sans_list
);
4131 /*************************************************************
4134 * Initialize FreeType library and create a list of available faces
4136 BOOL
WineEngInit(void)
4141 /* update locale dependent font info in registry */
4144 if(!init_freetype()) return FALSE
;
4146 #ifdef SONAME_LIBFONTCONFIG
4150 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
4152 ERR("Failed to create font mutex\n");
4155 WaitForSingleObject(font_mutex
, INFINITE
);
4157 create_font_cache_key(&hkey_font_cache
, &disposition
);
4159 if(disposition
== REG_CREATED_NEW_KEY
)
4162 load_font_list_from_cache(hkey_font_cache
);
4164 reorder_font_list();
4171 if(disposition
== REG_CREATED_NEW_KEY
)
4172 update_reg_entries();
4174 init_system_links();
4176 ReleaseMutex(font_mutex
);
4181 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
4184 TT_HoriHeader
*pHori
;
4187 const LONG MAX_PPEM
= (1 << 16) - 1;
4189 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4190 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4192 if(height
== 0) height
= 16;
4194 /* Calc. height of EM square:
4196 * For +ve lfHeight we have
4197 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4198 * Re-arranging gives:
4199 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4201 * For -ve lfHeight we have
4203 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4204 * with il = winAscent + winDescent - units_per_em]
4209 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
4210 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4211 pHori
->Ascender
- pHori
->Descender
);
4213 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4214 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
4215 if(ppem
> MAX_PPEM
) {
4216 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4220 else if(height
>= -MAX_PPEM
)
4223 WARN("Ignoring too large height %d\n", height
);
4230 static struct font_mapping
*map_font_file( const char *name
)
4232 struct font_mapping
*mapping
;
4236 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4237 if (fstat( fd
, &st
) == -1) goto error
;
4239 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4241 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4243 mapping
->refcount
++;
4248 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4251 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4254 if (mapping
->data
== MAP_FAILED
)
4256 HeapFree( GetProcessHeap(), 0, mapping
);
4259 mapping
->refcount
= 1;
4260 mapping
->dev
= st
.st_dev
;
4261 mapping
->ino
= st
.st_ino
;
4262 mapping
->size
= st
.st_size
;
4263 list_add_tail( &mappings_list
, &mapping
->entry
);
4271 static void unmap_font_file( struct font_mapping
*mapping
)
4273 if (!--mapping
->refcount
)
4275 list_remove( &mapping
->entry
);
4276 munmap( mapping
->data
, mapping
->size
);
4277 HeapFree( GetProcessHeap(), 0, mapping
);
4281 static LONG
load_VDMX(GdiFont
*, LONG
);
4283 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4290 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4294 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4295 font
->mapping
= map_font_file( filename
);
4296 HeapFree( GetProcessHeap(), 0, filename
);
4299 WARN("failed to map %s\n", debugstr_w(face
->file
));
4302 data_ptr
= font
->mapping
->data
;
4303 data_size
= font
->mapping
->size
;
4307 data_ptr
= face
->font_data_ptr
;
4308 data_size
= face
->font_data_size
;
4311 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4313 ERR("FT_New_Face rets %d\n", err
);
4317 /* set it here, as load_VDMX needs it */
4318 font
->ft_face
= ft_face
;
4320 if(FT_IS_SCALABLE(ft_face
)) {
4321 /* load the VDMX table if we have one */
4322 font
->ppem
= load_VDMX(font
, height
);
4324 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4325 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4327 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4328 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4330 font
->ppem
= height
;
4331 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4332 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4338 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4340 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4341 a single face with the requested charset. The idea is to check if
4342 the selected font supports the current ANSI codepage, if it does
4343 return the corresponding charset, else return the first charset */
4346 int acp
= GetACP(), i
;
4350 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4352 const SYSTEM_LINKS
*font_link
;
4354 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4355 return csi
.ciCharset
;
4357 font_link
= find_font_link(family_name
);
4358 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4359 return csi
.ciCharset
;
4362 for(i
= 0; i
< 32; i
++) {
4364 if(face
->fs
.fsCsb
[0] & fs0
) {
4365 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4367 return csi
.ciCharset
;
4370 FIXME("TCI failing on %x\n", fs0
);
4374 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4375 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4377 return DEFAULT_CHARSET
;
4380 static GdiFont
*alloc_font(void)
4382 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4385 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4386 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4388 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4389 ret
->total_kern_pairs
= (DWORD
)-1;
4390 ret
->kern_pairs
= NULL
;
4391 list_init(&ret
->child_fonts
);
4395 static void free_font(GdiFont
*font
)
4397 CHILD_FONT
*child
, *child_next
;
4400 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4402 list_remove(&child
->entry
);
4404 free_font(child
->font
);
4405 release_face( child
->face
);
4406 HeapFree(GetProcessHeap(), 0, child
);
4409 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4410 if (font
->mapping
) unmap_font_file( font
->mapping
);
4411 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4412 HeapFree(GetProcessHeap(), 0, font
->potm
);
4413 HeapFree(GetProcessHeap(), 0, font
->name
);
4414 for (i
= 0; i
< font
->gmsize
; i
++)
4415 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4416 HeapFree(GetProcessHeap(), 0, font
->gm
);
4417 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4418 HeapFree(GetProcessHeap(), 0, font
);
4422 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4424 FT_Face ft_face
= font
->ft_face
;
4428 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4435 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4437 /* make sure value of len is the value freetype says it needs */
4440 FT_ULong needed
= 0;
4441 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4442 if( !err
&& needed
< len
) len
= needed
;
4444 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4447 TRACE("Can't find table %c%c%c%c\n",
4448 /* bytes were reversed */
4449 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4450 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4456 /*************************************************************
4459 * load the vdmx entry for the specified height
4462 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4463 ( ( (FT_ULong)_x4 << 24 ) | \
4464 ( (FT_ULong)_x3 << 16 ) | \
4465 ( (FT_ULong)_x2 << 8 ) | \
4468 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4483 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4487 BYTE devXRatio
, devYRatio
;
4488 USHORT numRecs
, numRatios
;
4489 DWORD result
, offset
= -1;
4493 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4495 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4498 /* FIXME: need the real device aspect ratio */
4502 numRecs
= GET_BE_WORD(hdr
[1]);
4503 numRatios
= GET_BE_WORD(hdr
[2]);
4505 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4506 for(i
= 0; i
< numRatios
; i
++) {
4509 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4510 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4513 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4515 if((ratio
.xRatio
== 0 &&
4516 ratio
.yStartRatio
== 0 &&
4517 ratio
.yEndRatio
== 0) ||
4518 (devXRatio
== ratio
.xRatio
&&
4519 devYRatio
>= ratio
.yStartRatio
&&
4520 devYRatio
<= ratio
.yEndRatio
))
4522 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4523 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4524 offset
= GET_BE_WORD(tmp
);
4530 FIXME("No suitable ratio found\n");
4534 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4536 BYTE startsz
, endsz
;
4539 recs
= GET_BE_WORD(group
.recs
);
4540 startsz
= group
.startsz
;
4541 endsz
= group
.endsz
;
4543 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4545 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4546 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4547 if(result
== GDI_ERROR
) {
4548 FIXME("Failed to retrieve vTable\n");
4553 for(i
= 0; i
< recs
; i
++) {
4554 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4555 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4556 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4558 if(yMax
+ -yMin
== height
) {
4561 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4564 if(yMax
+ -yMin
> height
) {
4567 goto end
; /* failed */
4569 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4570 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4571 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4572 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4578 TRACE("ppem not found for height %d\n", height
);
4582 if(ppem
< startsz
|| ppem
> endsz
)
4588 for(i
= 0; i
< recs
; i
++) {
4590 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4592 if(yPelHeight
> ppem
)
4598 if(yPelHeight
== ppem
) {
4599 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4600 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4601 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4607 HeapFree(GetProcessHeap(), 0, vTable
);
4613 static void dump_gdi_font_list(void)
4617 TRACE("---------- Font Cache ----------\n");
4618 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4619 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4620 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4623 static void grab_font( GdiFont
*font
)
4625 if (!font
->refcount
++)
4627 list_remove( &font
->unused_entry
);
4628 unused_font_count
--;
4632 static void release_font( GdiFont
*font
)
4635 if (!--font
->refcount
)
4637 TRACE( "font %p\n", font
);
4639 /* add it to the unused list */
4640 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4641 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4643 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4644 TRACE( "freeing %p\n", font
);
4645 list_remove( &font
->entry
);
4646 list_remove( &font
->unused_entry
);
4649 else unused_font_count
++;
4651 if (TRACE_ON(font
)) dump_gdi_font_list();
4655 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4657 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4658 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4659 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4660 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4661 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4664 static void calc_hash(FONT_DESC
*pfd
)
4666 DWORD hash
= 0, *ptr
, two_chars
;
4670 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4672 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4674 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4676 pwc
= (WCHAR
*)&two_chars
;
4678 *pwc
= toupperW(*pwc
);
4680 *pwc
= toupperW(*pwc
);
4684 hash
^= !pfd
->can_use_bitmap
;
4689 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4696 fd
.can_use_bitmap
= can_use_bitmap
;
4699 /* try the in-use list */
4700 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4702 if(fontcmp(ret
, &fd
)) continue;
4703 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4704 list_remove( &ret
->entry
);
4705 list_add_head( &gdi_font_list
, &ret
->entry
);
4712 static void add_to_cache(GdiFont
*font
)
4714 static DWORD cache_num
= 1;
4716 font
->cache_num
= cache_num
++;
4717 list_add_head(&gdi_font_list
, &font
->entry
);
4718 TRACE( "font %p\n", font
);
4721 /*************************************************************
4722 * create_child_font_list
4724 static BOOL
create_child_font_list(GdiFont
*font
)
4727 SYSTEM_LINKS
*font_link
;
4728 CHILD_FONT
*font_link_entry
, *new_child
;
4732 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4733 font_name
= psub
? psub
->to
.name
: font
->name
;
4734 font_link
= find_font_link(font_name
);
4735 if (font_link
!= NULL
)
4737 TRACE("found entry in system list\n");
4738 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4740 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4741 new_child
->face
= font_link_entry
->face
;
4742 new_child
->font
= NULL
;
4743 new_child
->face
->refcount
++;
4744 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4745 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4750 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4751 * Sans Serif. This is how asian windows get default fallbacks for fonts
4753 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4754 font
->charset
!= OEM_CHARSET
&&
4755 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4757 font_link
= find_font_link(szDefaultFallbackLink
);
4758 if (font_link
!= NULL
)
4760 TRACE("found entry in default fallback list\n");
4761 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4763 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4764 new_child
->face
= font_link_entry
->face
;
4765 new_child
->font
= NULL
;
4766 new_child
->face
->refcount
++;
4767 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4768 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4777 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4779 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4781 if (pFT_Set_Charmap
)
4784 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4786 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4788 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4790 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4792 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4793 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4795 switch (ft_face
->charmaps
[i
]->platform_id
)
4798 cmap_def
= ft_face
->charmaps
[i
];
4800 case 0: /* Apple Unicode */
4801 cmap0
= ft_face
->charmaps
[i
];
4803 case 1: /* Macintosh */
4804 cmap1
= ft_face
->charmaps
[i
];
4807 cmap2
= ft_face
->charmaps
[i
];
4809 case 3: /* Microsoft */
4810 cmap3
= ft_face
->charmaps
[i
];
4815 if (cmap3
) /* prefer Microsoft cmap table */
4816 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4818 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4820 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4822 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4824 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4826 return ft_err
== FT_Err_Ok
;
4829 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4833 /*************************************************************
4836 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4837 LPCWSTR output
, const DEVMODEW
*devmode
)
4839 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4841 if (!physdev
) return FALSE
;
4842 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4847 /*************************************************************
4850 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4852 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4853 release_font( physdev
->font
);
4854 HeapFree( GetProcessHeap(), 0, physdev
);
4858 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4860 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4861 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4862 const FT_Encoding
*encs
= regular_order
;
4864 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4868 if (select_charmap( face
, *encs
)) break;
4874 #define GASP_GRIDFIT 0x01
4875 #define GASP_DOGRAY 0x02
4876 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4878 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4881 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4882 WORD
*alloced
= NULL
, *ptr
= buf
;
4883 WORD num_recs
, version
;
4887 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4888 if (size
== GDI_ERROR
) return FALSE
;
4889 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4890 if (size
> sizeof(buf
))
4892 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4893 if (!ptr
) return FALSE
;
4896 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4898 version
= GET_BE_WORD( *ptr
++ );
4899 num_recs
= GET_BE_WORD( *ptr
++ );
4901 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4903 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4909 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4910 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4913 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4917 HeapFree( GetProcessHeap(), 0, alloced
);
4921 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4923 const GSUB_ScriptList
*script
;
4924 const GSUB_Script
*deflt
= NULL
;
4926 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4928 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4929 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4931 const GSUB_Script
*scr
;
4934 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4935 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4937 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4939 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4945 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4949 const GSUB_LangSys
*Lang
;
4951 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4953 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4955 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4956 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4958 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4961 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4964 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4970 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4973 const GSUB_FeatureList
*feature
;
4974 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4976 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4977 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4979 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4980 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4982 const GSUB_Feature
*feat
;
4983 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4990 static const char* get_opentype_script(const GdiFont
*font
)
4993 * I am not sure if this is the correct way to generate our script tag
4996 switch (font
->charset
)
4998 case ANSI_CHARSET
: return "latn";
4999 case BALTIC_CHARSET
: return "latn"; /* ?? */
5000 case CHINESEBIG5_CHARSET
: return "hani";
5001 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5002 case GB2312_CHARSET
: return "hani";
5003 case GREEK_CHARSET
: return "grek";
5004 case HANGUL_CHARSET
: return "hang";
5005 case RUSSIAN_CHARSET
: return "cyrl";
5006 case SHIFTJIS_CHARSET
: return "kana";
5007 case TURKISH_CHARSET
: return "latn"; /* ?? */
5008 case VIETNAMESE_CHARSET
: return "latn";
5009 case JOHAB_CHARSET
: return "latn"; /* ?? */
5010 case ARABIC_CHARSET
: return "arab";
5011 case HEBREW_CHARSET
: return "hebr";
5012 case THAI_CHARSET
: return "thai";
5013 default: return "latn";
5017 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
5019 const GSUB_Header
*header
;
5020 const GSUB_Script
*script
;
5021 const GSUB_LangSys
*language
;
5022 const GSUB_Feature
*feature
;
5024 if (!font
->GSUB_Table
)
5027 header
= font
->GSUB_Table
;
5029 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5032 TRACE("Script not found\n");
5035 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5038 TRACE("Language not found\n");
5041 feature
= GSUB_get_feature(header
, language
, "vrt2");
5043 feature
= GSUB_get_feature(header
, language
, "vert");
5046 TRACE("vrt2/vert feature not found\n");
5052 /*************************************************************
5053 * freetype_SelectFont
5055 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5057 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5059 Face
*face
, *best
, *best_bitmap
;
5060 Family
*family
, *last_resort_family
;
5061 const struct list
*face_list
;
5062 INT height
, width
= 0;
5063 unsigned int score
= 0, new_score
;
5064 signed int diff
= 0, newdiff
;
5065 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5069 FontSubst
*psub
= NULL
;
5070 DC
*dc
= get_dc_ptr( dev
->hdc
);
5071 const SYSTEM_LINKS
*font_link
;
5073 if (!hfont
) /* notification that the font has been changed by another driver */
5075 release_font( physdev
->font
);
5076 physdev
->font
= NULL
;
5077 release_dc_ptr( dc
);
5081 GetObjectW( hfont
, sizeof(lf
), &lf
);
5082 lf
.lfWidth
= abs(lf
.lfWidth
);
5084 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5086 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5087 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5088 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5091 if(dc
->GraphicsMode
== GM_ADVANCED
)
5093 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5094 /* Try to avoid not necessary glyph transformations */
5095 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5097 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5098 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5099 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5104 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5105 font scaling abilities. */
5106 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5107 dcmat
.eM21
= dcmat
.eM12
= 0;
5108 lf
.lfOrientation
= lf
.lfEscapement
;
5109 if (dc
->vport2WorldValid
)
5111 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5112 lf
.lfOrientation
= -lf
.lfOrientation
;
5113 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5114 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5118 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5119 dcmat
.eM21
, dcmat
.eM22
);
5122 EnterCriticalSection( &freetype_cs
);
5124 /* check the cache first */
5125 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5126 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5130 TRACE("not in cache\n");
5133 ret
->font_desc
.matrix
= dcmat
;
5134 ret
->font_desc
.lf
= lf
;
5135 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5136 calc_hash(&ret
->font_desc
);
5138 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5139 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5140 original value lfCharSet. Note this is a special case for
5141 Symbol and doesn't happen at least for "Wingdings*" */
5143 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5144 lf
.lfCharSet
= SYMBOL_CHARSET
;
5146 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5147 switch(lf
.lfCharSet
) {
5148 case DEFAULT_CHARSET
:
5149 csi
.fs
.fsCsb
[0] = 0;
5152 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5153 csi
.fs
.fsCsb
[0] = 0;
5159 if(lf
.lfFaceName
[0] != '\0') {
5160 CHILD_FONT
*font_link_entry
;
5161 LPWSTR FaceName
= lf
.lfFaceName
;
5163 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5166 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5167 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5168 if (psub
->to
.charset
!= -1)
5169 lf
.lfCharSet
= psub
->to
.charset
;
5172 /* We want a match on name and charset or just name if
5173 charset was DEFAULT_CHARSET. If the latter then
5174 we fixup the returned charset later in get_nearest_charset
5175 where we'll either use the charset of the current ansi codepage
5176 or if that's unavailable the first charset that the font supports.
5178 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5179 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5180 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5182 font_link
= find_font_link(family
->FamilyName
);
5183 face_list
= get_face_list_from_family(family
);
5184 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5185 if (!(face
->scalable
|| can_use_bitmap
))
5187 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5189 if (font_link
!= NULL
&&
5190 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5192 if (!csi
.fs
.fsCsb
[0])
5198 /* Search by full face name. */
5199 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5200 face_list
= get_face_list_from_family(family
);
5201 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5202 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5203 (face
->scalable
|| can_use_bitmap
))
5205 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5207 font_link
= find_font_link(family
->FamilyName
);
5208 if (font_link
!= NULL
&&
5209 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5216 * Try check the SystemLink list first for a replacement font.
5217 * We may find good replacements there.
5219 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5221 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5222 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5224 TRACE("found entry in system list\n");
5225 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5227 const SYSTEM_LINKS
*links
;
5229 face
= font_link_entry
->face
;
5230 if (!(face
->scalable
|| can_use_bitmap
))
5232 family
= face
->family
;
5233 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5235 links
= find_font_link(family
->FamilyName
);
5236 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5243 psub
= NULL
; /* substitution is no more relevant */
5245 /* If requested charset was DEFAULT_CHARSET then try using charset
5246 corresponding to the current ansi codepage */
5247 if (!csi
.fs
.fsCsb
[0])
5250 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5251 FIXME("TCI failed on codepage %d\n", acp
);
5252 csi
.fs
.fsCsb
[0] = 0;
5254 lf
.lfCharSet
= csi
.ciCharset
;
5257 want_vertical
= (lf
.lfFaceName
[0] == '@');
5259 /* Face families are in the top 4 bits of lfPitchAndFamily,
5260 so mask with 0xF0 before testing */
5262 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5263 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5264 strcpyW(lf
.lfFaceName
, defFixed
);
5265 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5266 strcpyW(lf
.lfFaceName
, defSerif
);
5267 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5268 strcpyW(lf
.lfFaceName
, defSans
);
5270 strcpyW(lf
.lfFaceName
, defSans
);
5271 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5272 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5273 font_link
= find_font_link(family
->FamilyName
);
5274 face_list
= get_face_list_from_family(family
);
5275 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5276 if (!(face
->scalable
|| can_use_bitmap
))
5278 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5280 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5286 last_resort_family
= NULL
;
5287 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5288 font_link
= find_font_link(family
->FamilyName
);
5289 face_list
= get_face_list_from_family(family
);
5290 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5291 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5292 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5293 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5296 if(can_use_bitmap
&& !last_resort_family
)
5297 last_resort_family
= family
;
5302 if(last_resort_family
) {
5303 family
= last_resort_family
;
5304 csi
.fs
.fsCsb
[0] = 0;
5308 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5309 face_list
= get_face_list_from_family(family
);
5310 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5311 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5312 csi
.fs
.fsCsb
[0] = 0;
5313 WARN("just using first face for now\n");
5316 if(can_use_bitmap
&& !last_resort_family
)
5317 last_resort_family
= family
;
5320 if(!last_resort_family
) {
5321 FIXME("can't find a single appropriate font - bailing\n");
5327 WARN("could only find a bitmap font - this will probably look awful!\n");
5328 family
= last_resort_family
;
5329 csi
.fs
.fsCsb
[0] = 0;
5332 it
= lf
.lfItalic
? 1 : 0;
5333 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5335 height
= lf
.lfHeight
;
5337 face
= best
= best_bitmap
= NULL
;
5338 font_link
= find_font_link(family
->FamilyName
);
5339 face_list
= get_face_list_from_family(family
);
5340 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5342 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5343 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5348 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5349 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5350 new_score
= (italic
^ it
) + (bold
^ bd
);
5351 if(!best
|| new_score
<= score
)
5353 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5354 italic
, bold
, it
, bd
);
5357 if(best
->scalable
&& score
== 0) break;
5361 newdiff
= height
- (signed int)(best
->size
.height
);
5363 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5364 if(!best_bitmap
|| new_score
< score
||
5365 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5367 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5370 if(score
== 0 && diff
== 0) break;
5377 face
= best
->scalable
? best
: best_bitmap
;
5378 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5379 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5382 height
= lf
.lfHeight
;
5386 if(csi
.fs
.fsCsb
[0]) {
5387 ret
->charset
= lf
.lfCharSet
;
5388 ret
->codepage
= csi
.ciACP
;
5391 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5393 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5394 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5396 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5398 if(!face
->scalable
) {
5399 /* Windows uses integer scaling factors for bitmap fonts */
5400 INT scale
, scaled_height
;
5401 GdiFont
*cachedfont
;
5403 /* FIXME: rotation of bitmap fonts is ignored */
5404 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5406 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5407 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5408 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5409 /* As we changed the matrix, we need to search the cache for the font again,
5410 * otherwise we might explode the cache. */
5411 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5412 TRACE("Found cached font after non-scalable matrix rescale!\n");
5417 calc_hash(&ret
->font_desc
);
5419 if (height
!= 0) height
= diff
;
5420 height
+= face
->size
.height
;
5422 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5423 scaled_height
= scale
* face
->size
.height
;
5424 /* Only jump to the next height if the difference <= 25% original height */
5425 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5426 /* The jump between unscaled and doubled is delayed by 1 */
5427 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5428 ret
->scale_y
= scale
;
5430 width
= face
->size
.x_ppem
>> 6;
5431 height
= face
->size
.y_ppem
>> 6;
5435 TRACE("font scale y: %f\n", ret
->scale_y
);
5437 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5446 ret
->ntmFlags
= face
->ntmFlags
;
5448 pick_charmap( ret
->ft_face
, ret
->charset
);
5450 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5451 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5452 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5453 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5454 create_child_font_list(ret
);
5456 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5458 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5459 if (length
!= GDI_ERROR
)
5461 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5462 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5463 TRACE("Loaded GSUB table of %i bytes\n",length
);
5464 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5465 if (!ret
->vert_feature
)
5467 TRACE("Vertical feature not found\n");
5468 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5469 ret
->GSUB_Table
= NULL
;
5473 ret
->aa_flags
= HIWORD( face
->flags
);
5475 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5481 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5483 switch (lf
.lfQuality
)
5485 case NONANTIALIASED_QUALITY
:
5486 case ANTIALIASED_QUALITY
:
5487 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5489 case CLEARTYPE_QUALITY
:
5490 case CLEARTYPE_NATURAL_QUALITY
:
5492 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5493 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5495 /* fixup the antialiasing flags for that font */
5498 case WINE_GGO_HRGB_BITMAP
:
5499 case WINE_GGO_HBGR_BITMAP
:
5500 case WINE_GGO_VRGB_BITMAP
:
5501 case WINE_GGO_VBGR_BITMAP
:
5502 if (is_subpixel_rendering_enabled()) break;
5503 *aa_flags
= GGO_GRAY4_BITMAP
;
5505 case GGO_GRAY2_BITMAP
:
5506 case GGO_GRAY4_BITMAP
:
5507 case GGO_GRAY8_BITMAP
:
5508 case WINE_GGO_GRAY16_BITMAP
:
5509 if (is_hinting_enabled())
5512 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5514 TRACE( "font %s %d aa disabled by GASP\n",
5515 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5516 *aa_flags
= GGO_BITMAP
;
5521 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5522 release_font( physdev
->font
);
5523 physdev
->font
= ret
;
5525 LeaveCriticalSection( &freetype_cs
);
5526 release_dc_ptr( dc
);
5527 return ret
? hfont
: 0;
5530 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5537 id
+= IDS_FIRST_SCRIPT
;
5538 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5539 if (!rsrc
) return 0;
5540 hMem
= LoadResource( gdi32_module
, rsrc
);
5541 if (!hMem
) return 0;
5543 p
= LockResource( hMem
);
5545 while (id
--) p
+= *p
+ 1;
5547 i
= min(LF_FACESIZE
- 1, *p
);
5548 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5554 /***************************************************
5555 * create_enum_charset_list
5557 * This function creates charset enumeration list because in DEFAULT_CHARSET
5558 * case, the ANSI codepage's charset takes precedence over other charsets.
5559 * This function works as a filter other than DEFAULT_CHARSET case.
5561 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5566 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5567 csi
.fs
.fsCsb
[0] != 0) {
5568 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5569 list
->element
[n
].charset
= csi
.ciCharset
;
5570 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5573 else { /* charset is DEFAULT_CHARSET or invalid. */
5577 /* Set the current codepage's charset as the first element. */
5579 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5580 csi
.fs
.fsCsb
[0] != 0) {
5581 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5582 list
->element
[n
].charset
= csi
.ciCharset
;
5583 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5584 mask
|= csi
.fs
.fsCsb
[0];
5588 /* Fill out left elements. */
5589 for (i
= 0; i
< 32; i
++) {
5591 fs
.fsCsb
[0] = 1L << i
;
5593 if (fs
.fsCsb
[0] & mask
)
5594 continue; /* skip, already added. */
5595 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5596 continue; /* skip, this is an invalid fsCsb bit. */
5598 list
->element
[n
].mask
= fs
.fsCsb
[0];
5599 list
->element
[n
].charset
= csi
.ciCharset
;
5600 load_script_name( i
, list
->element
[n
].name
);
5601 mask
|= fs
.fsCsb
[0];
5605 /* add catch all mask for remaining bits */
5608 list
->element
[n
].mask
= ~mask
;
5609 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5610 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5619 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5620 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5625 if (face
->cached_enum_data
)
5628 *pelf
= face
->cached_enum_data
->elf
;
5629 *pntm
= face
->cached_enum_data
->ntm
;
5630 *ptype
= face
->cached_enum_data
->type
;
5634 font
= alloc_font();
5636 if(face
->scalable
) {
5640 height
= face
->size
.y_ppem
>> 6;
5641 width
= face
->size
.x_ppem
>> 6;
5643 font
->scale_y
= 1.0;
5645 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5651 font
->name
= strdupW( family_name
);
5652 font
->ntmFlags
= face
->ntmFlags
;
5654 if (get_outline_text_metrics(font
))
5656 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5658 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5659 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5660 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5662 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5663 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5665 lstrcpynW(pelf
->elfFullName
,
5666 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5668 lstrcpynW(pelf
->elfStyle
,
5669 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5674 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5676 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5677 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5678 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5680 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5682 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5684 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5685 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5688 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5689 pntm
->ntmFontSig
= face
->fs
;
5691 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5693 pelf
->elfLogFont
.lfEscapement
= 0;
5694 pelf
->elfLogFont
.lfOrientation
= 0;
5695 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5696 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5697 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5698 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5699 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5700 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5701 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5702 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5703 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5704 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5705 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5708 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5709 *ptype
|= TRUETYPE_FONTTYPE
;
5710 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5711 *ptype
|= DEVICE_FONTTYPE
;
5712 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5713 *ptype
|= RASTER_FONTTYPE
;
5715 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5716 if (face
->cached_enum_data
)
5718 face
->cached_enum_data
->elf
= *pelf
;
5719 face
->cached_enum_data
->ntm
= *pntm
;
5720 face
->cached_enum_data
->type
= *ptype
;
5726 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5729 const struct list
*face_list
;
5731 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5733 face_list
= get_face_list_from_family(family
);
5734 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5735 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5740 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5742 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5744 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5747 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5748 FONTENUMPROCW proc
, LPARAM lparam
)
5751 NEWTEXTMETRICEXW ntm
;
5755 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5756 for(i
= 0; i
< list
->total
; i
++) {
5757 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5758 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5759 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5760 i
= list
->total
; /* break out of loop after enumeration */
5764 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5765 /* use the DEFAULT_CHARSET case only if no other charset is present */
5766 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5767 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5768 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5769 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5770 if (!elf
.elfScript
[0])
5771 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5773 /* Font Replacement */
5774 if (family
!= face
->family
)
5776 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5778 strcpyW(elf
.elfFullName
, face
->FullName
);
5780 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5782 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5783 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5784 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5785 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5786 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5787 ntm
.ntmTm
.ntmFlags
);
5788 /* release section before callback (FIXME) */
5789 LeaveCriticalSection( &freetype_cs
);
5790 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5791 EnterCriticalSection( &freetype_cs
);
5796 /*************************************************************
5797 * freetype_EnumFonts
5799 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5803 const struct list
*face_list
;
5805 struct enum_charset_list enum_charsets
;
5809 lf
.lfCharSet
= DEFAULT_CHARSET
;
5810 lf
.lfPitchAndFamily
= 0;
5811 lf
.lfFaceName
[0] = 0;
5815 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5817 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5820 EnterCriticalSection( &freetype_cs
);
5821 if(plf
->lfFaceName
[0]) {
5823 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5826 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5827 debugstr_w(psub
->to
.name
));
5829 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5833 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5834 if (!family_matches(family
, plf
)) continue;
5835 face_list
= get_face_list_from_family(family
);
5836 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5837 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5838 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5842 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5843 face_list
= get_face_list_from_family(family
);
5844 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5845 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5848 LeaveCriticalSection( &freetype_cs
);
5852 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5854 pt
->x
.value
= vec
->x
>> 6;
5855 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5856 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5857 pt
->y
.value
= vec
->y
>> 6;
5858 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5859 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5863 /***************************************************
5864 * According to the MSDN documentation on WideCharToMultiByte,
5865 * certain codepages cannot set the default_used parameter.
5866 * This returns TRUE if the codepage can set that parameter, false else
5867 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5869 static BOOL
codepage_sets_default_used(UINT codepage
)
5883 * GSUB Table handling functions
5886 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5888 const GSUB_CoverageFormat1
* cf1
;
5892 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5894 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5896 TRACE("Coverage Format 1, %i glyphs\n",count
);
5897 for (i
= 0; i
< count
; i
++)
5898 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5902 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5904 const GSUB_CoverageFormat2
* cf2
;
5907 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5909 count
= GET_BE_WORD(cf2
->RangeCount
);
5910 TRACE("Coverage Format 2, %i ranges\n",count
);
5911 for (i
= 0; i
< count
; i
++)
5913 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5915 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5916 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5918 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5919 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5925 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5930 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5934 const GSUB_LookupList
*lookup
;
5935 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5937 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5938 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5940 const GSUB_LookupTable
*look
;
5941 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5942 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5943 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5944 if (GET_BE_WORD(look
->LookupType
) != 1)
5945 FIXME("We only handle SubType 1\n");
5950 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5952 const GSUB_SingleSubstFormat1
*ssf1
;
5953 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5954 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5955 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5957 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5958 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5959 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5961 TRACE(" Glyph 0x%x ->",glyph
);
5962 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5963 TRACE(" 0x%x\n",glyph
);
5968 const GSUB_SingleSubstFormat2
*ssf2
;
5972 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5973 offset
= GET_BE_WORD(ssf1
->Coverage
);
5974 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5975 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5976 TRACE(" Coverage index %i\n",index
);
5979 TRACE(" Glyph is 0x%x ->",glyph
);
5980 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5981 TRACE("0x%x\n",glyph
);
5991 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5993 const GSUB_Header
*header
;
5994 const GSUB_Feature
*feature
;
5996 if (!font
->GSUB_Table
)
5999 header
= font
->GSUB_Table
;
6000 feature
= font
->vert_feature
;
6002 return GSUB_apply_feature(header
, feature
, glyph
);
6005 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
6009 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6010 WCHAR wc
= (WCHAR
)glyph
;
6012 BOOL
*default_used_pointer
;
6015 default_used_pointer
= NULL
;
6016 default_used
= FALSE
;
6017 if (codepage_sets_default_used(font
->codepage
))
6018 default_used_pointer
= &default_used
;
6019 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6021 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6022 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6027 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6028 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
6032 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6034 if (glyph
< 0x100) glyph
+= 0xf000;
6035 /* there is a number of old pre-Unicode "broken" TTFs, which
6036 do have symbols at U+00XX instead of U+f0XX */
6037 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6038 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6040 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6045 static FT_UInt
get_default_char_index(GdiFont
*font
)
6047 FT_UInt default_char
;
6049 if (FT_IS_SFNT(font
->ft_face
))
6051 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6052 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6057 get_text_metrics(font
, &textm
);
6058 default_char
= textm
.tmDefaultChar
;
6061 return default_char
;
6064 /*************************************************************
6065 * freetype_GetGlyphIndices
6067 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6069 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6072 BOOL got_default
= FALSE
;
6076 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6077 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6080 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6082 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6087 EnterCriticalSection( &freetype_cs
);
6089 for(i
= 0; i
< count
; i
++)
6091 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
6096 default_char
= get_default_char_index(physdev
->font
);
6099 pgi
[i
] = default_char
;
6102 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6104 LeaveCriticalSection( &freetype_cs
);
6108 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6110 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6111 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6114 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6116 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6117 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6120 static inline BYTE
get_max_level( UINT format
)
6124 case GGO_GRAY2_BITMAP
: return 4;
6125 case GGO_GRAY4_BITMAP
: return 16;
6126 case GGO_GRAY8_BITMAP
: return 64;
6131 static const struct { WCHAR lower
; WCHAR upper
;} unrotate_ranges
[] =
6138 /* General Punctuation */
6140 /* Currency Symbols */
6141 /* Combining Diacritical Marks for Symbols */
6142 /* Letterlike Symbols */
6144 /* Enclosed Alphanumerics */
6146 /* Geometric Shapes */
6147 /* Miscellaneous Symbols */
6149 /* Miscellaneous Mathematical Symbols-A */
6150 /* Supplemental Arrows-A */
6152 /* East Asian scripts and symbols */
6154 /* Hangul Syllables */
6155 /* Hangul Jamo Extended-B */
6157 /* CJK Compatibility Ideographs */
6159 /* Vertical Forms */
6160 /* Combining Half Marks */
6161 /* CJK Compatibility Forms */
6163 /* Halfwidth and Fullwidth Forms */
6167 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6172 if (uchar
< unrotate_ranges
[i
].lower
)
6175 if (uchar
>= unrotate_ranges
[i
].lower
&& uchar
<= unrotate_ranges
[i
].upper
)
6180 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6182 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6183 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6186 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6187 FT_Face ft_face
= incoming_font
->ft_face
;
6188 GdiFont
*font
= incoming_font
;
6189 FT_Glyph_Metrics metrics
;
6190 FT_UInt glyph_index
;
6191 DWORD width
, height
, pitch
, needed
= 0;
6192 FT_Bitmap ft_bitmap
;
6194 INT left
, right
, top
= 0, bottom
= 0, adv
;
6195 INT origin_x
= 0, origin_y
= 0;
6197 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6198 double widthRatio
= 1.0;
6199 FT_Matrix transMat
= identityMat
;
6200 FT_Matrix transMatUnrotated
;
6201 FT_Matrix transMatTategaki
;
6202 BOOL needsTransform
= FALSE
;
6203 BOOL tategaki
= (font
->name
[0] == '@');
6204 BOOL vertical_metrics
;
6205 UINT original_index
;
6206 LONG avgAdvance
= 0;
6209 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6210 buflen
, buf
, lpmat
);
6212 TRACE("font transform %f %f %f %f\n",
6213 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6214 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6216 if(format
& GGO_GLYPH_INDEX
) {
6217 glyph_index
= glyph
;
6218 original_index
= glyph
;
6219 format
&= ~GGO_GLYPH_INDEX
;
6220 /* TODO: Window also turns off tategaki for glyphs passed in by index
6221 if their unicode code points fall outside of the range that is
6225 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6226 ft_face
= font
->ft_face
;
6227 original_index
= glyph_index
;
6228 /* We know what unicode ranges get rotated */
6229 if (!vert
&& tategaki
)
6230 tategaki
= check_unicode_tategaki(glyph
);
6233 if(format
& GGO_UNHINTED
) {
6234 load_flags
|= FT_LOAD_NO_HINTING
;
6235 format
&= ~GGO_UNHINTED
;
6238 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6239 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6240 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6241 font
->gmsize
* sizeof(GM
*));
6243 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6244 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6246 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6247 *abc
= FONT_GM(font
,original_index
)->abc
;
6248 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6249 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6250 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6251 return 1; /* FIXME */
6255 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6256 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6258 /* Scaling factor */
6263 get_text_metrics(font
, &tm
);
6265 widthRatio
= (double)font
->aveWidth
;
6266 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6269 widthRatio
= font
->scale_y
;
6271 /* Scaling transform */
6272 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6275 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6278 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6280 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6281 needsTransform
= TRUE
;
6284 /* Slant transform */
6285 if (font
->fake_italic
) {
6288 slantMat
.xx
= (1 << 16);
6289 slantMat
.xy
= ((1 << 16) >> 2);
6291 slantMat
.yy
= (1 << 16);
6292 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6293 needsTransform
= TRUE
;
6296 /* Rotation transform */
6297 transMatUnrotated
= transMat
;
6298 transMatTategaki
= transMat
;
6299 if(font
->orientation
|| tategaki
) {
6300 FT_Matrix rotationMat
;
6301 FT_Matrix taterotationMat
;
6304 double orient
= font
->orientation
/ 10.0;
6305 double tate_orient
= 0.f
;
6308 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6310 tate_orient
= font
->orientation
/10.0;
6314 angle
= FT_FixedFromFloat(orient
);
6315 pFT_Vector_Unit(&vecAngle
, angle
);
6316 rotationMat
.xx
= vecAngle
.x
;
6317 rotationMat
.xy
= -vecAngle
.y
;
6318 rotationMat
.yx
= -rotationMat
.xy
;
6319 rotationMat
.yy
= rotationMat
.xx
;
6321 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6326 angle
= FT_FixedFromFloat(tate_orient
);
6327 pFT_Vector_Unit(&vecAngle
, angle
);
6328 taterotationMat
.xx
= vecAngle
.x
;
6329 taterotationMat
.xy
= -vecAngle
.y
;
6330 taterotationMat
.yx
= -taterotationMat
.xy
;
6331 taterotationMat
.yy
= taterotationMat
.xx
;
6332 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6335 needsTransform
= TRUE
;
6338 /* World transform */
6339 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6342 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6343 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6344 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6345 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6346 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6347 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6348 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6349 needsTransform
= TRUE
;
6352 /* Extra transformation specified by caller */
6353 if (!is_identity_MAT2(lpmat
))
6356 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6357 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6358 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6359 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6360 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6361 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6362 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6363 needsTransform
= TRUE
;
6366 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6367 /* there is a freetype bug where vertical metrics are only
6368 properly scaled and correct in 2.4.0 or greater */
6369 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6370 vertical_metrics
= FALSE
;
6372 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6373 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6375 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6378 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6382 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6383 * by the text metrics. The proper behavior is to clip the glyph metrics to
6384 * fit within the maximums specified in the text metrics. */
6385 metrics
= ft_face
->glyph
->metrics
;
6386 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6387 get_bitmap_text_metrics(incoming_font
)) {
6388 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6389 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6390 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6391 metrics
.horiBearingY
= top
;
6392 metrics
.height
= top
- bottom
;
6394 /* TODO: Are we supposed to clip the width as well...? */
6395 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6398 if(FT_IS_SCALABLE(incoming_font
->ft_face
)) {
6400 if (get_text_metrics(incoming_font
, &tm
) &&
6401 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6402 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6403 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6405 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6406 TRACE("Fixed-pitch full-width character detected\n");
6408 avgAdvance
= 0; /* cancel this feature */
6412 if(!needsTransform
) {
6413 left
= (INT
)(metrics
.horiBearingX
) & -64;
6414 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6416 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6418 adv
= (INT
)avgAdvance
* 2;
6420 top
= (metrics
.horiBearingY
+ 63) & -64;
6421 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6422 lpgm
->gmCellIncX
= adv
;
6423 lpgm
->gmCellIncY
= 0;
6432 for(xc
= 0; xc
< 2; xc
++) {
6433 for(yc
= 0; yc
< 2; yc
++) {
6434 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6435 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6436 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6437 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6438 if(xc
== 0 && yc
== 0) {
6439 left
= right
= vec
.x
;
6440 top
= bottom
= vec
.y
;
6442 if(vec
.x
< left
) left
= vec
.x
;
6443 else if(vec
.x
> right
) right
= vec
.x
;
6444 if(vec
.y
< bottom
) bottom
= vec
.y
;
6445 else if(vec
.y
> top
) top
= vec
.y
;
6450 right
= (right
+ 63) & -64;
6451 bottom
= bottom
& -64;
6452 top
= (top
+ 63) & -64;
6456 for(xc
= 0; xc
< 2; xc
++)
6458 for(yc
= 0; yc
< 2; yc
++)
6460 if (vertical_metrics
)
6462 vec
.x
= metrics
.vertBearingY
+ xc
* metrics
.height
;
6463 vec
.y
= metrics
.horiBearingX
- yc
* (metrics
.vertBearingX
* 2);
6467 vec
.x
= metrics
.horiBearingY
- xc
* metrics
.height
;
6468 vec
.y
= metrics
.horiBearingX
+ yc
* metrics
.width
;
6471 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
6472 pFT_Vector_Transform(&vec
, &transMat
);
6473 if(xc
== 0 && yc
== 0) {
6477 if(vec
.x
< origin_x
) origin_x
= vec
.x
;
6478 if(vec
.y
> origin_y
) origin_y
= vec
.y
;
6482 origin_x
= origin_x
& -64;
6483 origin_y
= (origin_y
+ 63) & -64;
6491 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6492 vec
.x
= metrics
.horiAdvance
;
6494 pFT_Vector_Transform(&vec
, &transMat
);
6495 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6496 if (!avgAdvance
|| vec
.y
)
6497 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6499 vec
.x
= incoming_font
->ntmAvgWidth
;
6501 pFT_Vector_Transform(&vec
, &transMat
);
6502 lpgm
->gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6505 if (vertical_metrics
)
6506 vec
.x
= metrics
.vertAdvance
;
6508 vec
.x
= metrics
.horiAdvance
;
6510 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6511 if (!avgAdvance
|| vec
.y
)
6512 adv
= (vec
.x
+63) >> 6;
6514 vec
.x
= incoming_font
->ntmAvgWidth
;
6516 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6517 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6521 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6522 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6523 lpgm
->gmptGlyphOrigin
.x
= origin_x
>> 6;
6524 lpgm
->gmptGlyphOrigin
.y
= origin_y
>> 6;
6525 abc
->abcA
= left
>> 6;
6526 abc
->abcB
= (right
- left
) >> 6;
6527 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6529 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6530 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6531 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6533 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6534 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6536 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6537 FONT_GM(font
,original_index
)->abc
= *abc
;
6538 FONT_GM(font
,original_index
)->init
= TRUE
;
6541 if(format
== GGO_METRICS
)
6543 return 1; /* FIXME */
6546 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6547 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6549 TRACE("loaded a bitmap\n");
6555 width
= lpgm
->gmBlackBoxX
;
6556 height
= lpgm
->gmBlackBoxY
;
6557 pitch
= ((width
+ 31) >> 5) << 2;
6558 needed
= pitch
* height
;
6560 if(!buf
|| !buflen
) break;
6562 switch(ft_face
->glyph
->format
) {
6563 case ft_glyph_format_bitmap
:
6565 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6566 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6567 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6569 memcpy(dst
, src
, w
);
6570 src
+= ft_face
->glyph
->bitmap
.pitch
;
6576 case ft_glyph_format_outline
:
6577 ft_bitmap
.width
= width
;
6578 ft_bitmap
.rows
= height
;
6579 ft_bitmap
.pitch
= pitch
;
6580 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6581 ft_bitmap
.buffer
= buf
;
6584 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6586 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6588 /* Note: FreeType will only set 'black' bits for us. */
6589 memset(buf
, 0, needed
);
6590 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6594 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6599 case GGO_GRAY2_BITMAP
:
6600 case GGO_GRAY4_BITMAP
:
6601 case GGO_GRAY8_BITMAP
:
6602 case WINE_GGO_GRAY16_BITMAP
:
6604 unsigned int max_level
, row
, col
;
6607 width
= lpgm
->gmBlackBoxX
;
6608 height
= lpgm
->gmBlackBoxY
;
6609 pitch
= (width
+ 3) / 4 * 4;
6610 needed
= pitch
* height
;
6612 if(!buf
|| !buflen
) break;
6614 max_level
= get_max_level( format
);
6616 switch(ft_face
->glyph
->format
) {
6617 case ft_glyph_format_bitmap
:
6619 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6620 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6622 memset( buf
, 0, needed
);
6624 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6625 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6626 src
+= ft_face
->glyph
->bitmap
.pitch
;
6631 case ft_glyph_format_outline
:
6633 ft_bitmap
.width
= width
;
6634 ft_bitmap
.rows
= height
;
6635 ft_bitmap
.pitch
= pitch
;
6636 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6637 ft_bitmap
.buffer
= buf
;
6640 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6642 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6644 memset(ft_bitmap
.buffer
, 0, buflen
);
6646 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6648 if (max_level
!= 255)
6650 for (row
= 0, start
= buf
; row
< height
; row
++)
6652 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6653 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6661 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6667 case WINE_GGO_HRGB_BITMAP
:
6668 case WINE_GGO_HBGR_BITMAP
:
6669 case WINE_GGO_VRGB_BITMAP
:
6670 case WINE_GGO_VBGR_BITMAP
:
6671 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6673 switch (ft_face
->glyph
->format
)
6675 case FT_GLYPH_FORMAT_BITMAP
:
6680 width
= lpgm
->gmBlackBoxX
;
6681 height
= lpgm
->gmBlackBoxY
;
6683 needed
= pitch
* height
;
6685 if (!buf
|| !buflen
) break;
6687 memset(buf
, 0, buflen
);
6689 src
= ft_face
->glyph
->bitmap
.buffer
;
6690 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6692 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6695 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6697 if ( src
[x
/ 8] & masks
[x
% 8] )
6698 ((unsigned int *)dst
)[x
] = ~0u;
6707 case FT_GLYPH_FORMAT_OUTLINE
:
6711 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6712 INT x_shift
, y_shift
;
6714 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6715 FT_Render_Mode render_mode
=
6716 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6717 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6719 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6721 if ( render_mode
== FT_RENDER_MODE_LCD
)
6723 lpgm
->gmBlackBoxX
+= 2;
6724 lpgm
->gmptGlyphOrigin
.x
-= 1;
6728 lpgm
->gmBlackBoxY
+= 2;
6729 lpgm
->gmptGlyphOrigin
.y
+= 1;
6733 width
= lpgm
->gmBlackBoxX
;
6734 height
= lpgm
->gmBlackBoxY
;
6736 needed
= pitch
* height
;
6738 if (!buf
|| !buflen
) break;
6740 memset(buf
, 0, buflen
);
6742 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6744 if ( needsTransform
)
6745 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
6747 if ( pFT_Library_SetLcdFilter
)
6748 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6749 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6751 src
= ft_face
->glyph
->bitmap
.buffer
;
6752 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6753 src_width
= ft_face
->glyph
->bitmap
.width
;
6754 src_height
= ft_face
->glyph
->bitmap
.rows
;
6756 if ( render_mode
== FT_RENDER_MODE_LCD
)
6764 rgb_interval
= src_pitch
;
6769 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6772 src
+= hmul
* -x_shift
;
6773 src_width
-= hmul
* -x_shift
;
6775 else if ( x_shift
> 0 )
6781 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6784 src
+= src_pitch
* vmul
* -y_shift
;
6785 src_height
-= vmul
* -y_shift
;
6787 else if ( y_shift
> 0 )
6789 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
6793 width
= min( width
, src_width
/ hmul
);
6794 height
= min( height
, src_height
/ vmul
);
6798 for ( x
= 0; x
< width
; x
++ )
6802 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6803 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6804 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6805 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6809 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6810 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6811 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6812 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6815 src
+= src_pitch
* vmul
;
6816 dst
+= pitch
/ sizeof(*dst
);
6823 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6835 int contour
, point
= 0, first_pt
;
6836 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6837 TTPOLYGONHEADER
*pph
;
6839 DWORD pph_start
, cpfx
, type
;
6841 if(buflen
== 0) buf
= NULL
;
6843 if (needsTransform
&& buf
) {
6844 pFT_Outline_Transform(outline
, &transMatTategaki
);
6847 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6848 /* Ignore contours containing one point */
6849 if(point
== outline
->contours
[contour
]) {
6855 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6858 pph
->dwType
= TT_POLYGON_TYPE
;
6859 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6861 needed
+= sizeof(*pph
);
6863 while(point
<= outline
->contours
[contour
]) {
6864 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6865 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6866 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6870 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6873 } while(point
<= outline
->contours
[contour
] &&
6874 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6875 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6876 /* At the end of a contour Windows adds the start point, but
6878 if(point
> outline
->contours
[contour
] &&
6879 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6881 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6883 } else if(point
<= outline
->contours
[contour
] &&
6884 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6885 /* add closing pt for bezier */
6887 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6895 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6898 pph
->cb
= needed
- pph_start
;
6904 /* Convert the quadratic Beziers to cubic Beziers.
6905 The parametric eqn for a cubic Bezier is, from PLRM:
6906 r(t) = at^3 + bt^2 + ct + r0
6907 with the control points:
6912 A quadratic Bezier has the form:
6913 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6915 So equating powers of t leads to:
6916 r1 = 2/3 p1 + 1/3 p0
6917 r2 = 2/3 p1 + 1/3 p2
6918 and of course r0 = p0, r3 = p2
6921 int contour
, point
= 0, first_pt
;
6922 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6923 TTPOLYGONHEADER
*pph
;
6925 DWORD pph_start
, cpfx
, type
;
6926 FT_Vector cubic_control
[4];
6927 if(buflen
== 0) buf
= NULL
;
6929 if (needsTransform
&& buf
) {
6930 pFT_Outline_Transform(outline
, &transMat
);
6933 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6935 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6938 pph
->dwType
= TT_POLYGON_TYPE
;
6939 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6941 needed
+= sizeof(*pph
);
6943 while(point
<= outline
->contours
[contour
]) {
6944 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6945 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6946 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6949 if(type
== TT_PRIM_LINE
) {
6951 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6955 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6958 /* FIXME: Possible optimization in endpoint calculation
6959 if there are two consecutive curves */
6960 cubic_control
[0] = outline
->points
[point
-1];
6961 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6962 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6963 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6964 cubic_control
[0].x
>>= 1;
6965 cubic_control
[0].y
>>= 1;
6967 if(point
+1 > outline
->contours
[contour
])
6968 cubic_control
[3] = outline
->points
[first_pt
];
6970 cubic_control
[3] = outline
->points
[point
+1];
6971 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6972 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6973 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6974 cubic_control
[3].x
>>= 1;
6975 cubic_control
[3].y
>>= 1;
6978 /* r1 = 1/3 p0 + 2/3 p1
6979 r2 = 1/3 p2 + 2/3 p1 */
6980 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6981 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6982 cubic_control
[2] = cubic_control
[1];
6983 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6984 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6985 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6986 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6988 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6989 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6990 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6995 } while(point
<= outline
->contours
[contour
] &&
6996 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6997 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6998 /* At the end of a contour Windows adds the start point,
6999 but only for Beziers and we've already done that.
7001 if(point
<= outline
->contours
[contour
] &&
7002 outline
->tags
[point
] & FT_Curve_Tag_On
) {
7003 /* This is the closing pt of a bezier, but we've already
7004 added it, so just inc point and carry on */
7011 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
7014 pph
->cb
= needed
- pph_start
;
7020 FIXME("Unsupported format %d\n", format
);
7026 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7028 FT_Face ft_face
= font
->ft_face
;
7029 FT_WinFNT_HeaderRec winfnt_header
;
7030 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7031 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7032 font
->potm
->otmSize
= size
;
7034 #define TM font->potm->otmTextMetrics
7035 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7037 TM
.tmHeight
= winfnt_header
.pixel_height
;
7038 TM
.tmAscent
= winfnt_header
.ascent
;
7039 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7040 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7041 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7042 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7043 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7044 TM
.tmWeight
= winfnt_header
.weight
;
7046 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7047 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7048 TM
.tmFirstChar
= winfnt_header
.first_char
;
7049 TM
.tmLastChar
= winfnt_header
.last_char
;
7050 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7051 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7052 TM
.tmItalic
= winfnt_header
.italic
;
7053 TM
.tmUnderlined
= font
->underline
;
7054 TM
.tmStruckOut
= font
->strikeout
;
7055 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7056 TM
.tmCharSet
= winfnt_header
.charset
;
7060 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7061 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7062 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7063 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7064 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7065 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7066 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7067 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7069 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7070 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7072 TM
.tmLastChar
= 255;
7073 TM
.tmDefaultChar
= 32;
7074 TM
.tmBreakChar
= 32;
7075 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7076 TM
.tmUnderlined
= font
->underline
;
7077 TM
.tmStruckOut
= font
->strikeout
;
7078 /* NB inverted meaning of TMPF_FIXED_PITCH */
7079 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
7080 TM
.tmCharSet
= font
->charset
;
7088 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7090 double scale_x
, scale_y
;
7094 scale_x
= (double)font
->aveWidth
;
7095 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7098 scale_x
= font
->scale_y
;
7100 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7101 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7103 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7104 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7106 SCALE_Y(ptm
->tmHeight
);
7107 SCALE_Y(ptm
->tmAscent
);
7108 SCALE_Y(ptm
->tmDescent
);
7109 SCALE_Y(ptm
->tmInternalLeading
);
7110 SCALE_Y(ptm
->tmExternalLeading
);
7111 SCALE_Y(ptm
->tmOverhang
);
7113 SCALE_X(ptm
->tmAveCharWidth
);
7114 SCALE_X(ptm
->tmMaxCharWidth
);
7120 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7122 double scale_x
, scale_y
;
7126 scale_x
= (double)font
->aveWidth
;
7127 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7130 scale_x
= font
->scale_y
;
7132 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7133 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7135 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7137 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7138 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7140 SCALE_Y(potm
->otmAscent
);
7141 SCALE_Y(potm
->otmDescent
);
7142 SCALE_Y(potm
->otmLineGap
);
7143 SCALE_Y(potm
->otmsCapEmHeight
);
7144 SCALE_Y(potm
->otmsXHeight
);
7145 SCALE_Y(potm
->otmrcFontBox
.top
);
7146 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7147 SCALE_X(potm
->otmrcFontBox
.left
);
7148 SCALE_X(potm
->otmrcFontBox
.right
);
7149 SCALE_Y(potm
->otmMacAscent
);
7150 SCALE_Y(potm
->otmMacDescent
);
7151 SCALE_Y(potm
->otmMacLineGap
);
7152 SCALE_X(potm
->otmptSubscriptSize
.x
);
7153 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7154 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7155 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7156 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7157 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7158 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7159 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7160 SCALE_Y(potm
->otmsStrikeoutSize
);
7161 SCALE_Y(potm
->otmsStrikeoutPosition
);
7162 SCALE_Y(potm
->otmsUnderscoreSize
);
7163 SCALE_Y(potm
->otmsUnderscorePosition
);
7169 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7173 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7175 /* Make sure that the font has sane width/height ratio */
7178 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7180 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7185 *ptm
= font
->potm
->otmTextMetrics
;
7186 scale_font_metrics(font
, ptm
);
7190 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7194 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7196 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7202 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7205 FT_Face ft_face
= font
->ft_face
;
7206 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7208 TT_HoriHeader
*pHori
;
7209 TT_Postscript
*pPost
;
7211 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7213 INT ascent
, descent
;
7215 TRACE("font=%p\n", font
);
7217 if(!FT_IS_SCALABLE(ft_face
))
7220 needed
= sizeof(*font
->potm
);
7222 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7223 family_nameW
= strdupW(font
->name
);
7225 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7228 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7229 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7231 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7233 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7236 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7237 face_nameW
= strdupW(font
->name
);
7239 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7240 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7242 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7245 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7246 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7247 full_nameW
= strdupW(fake_nameW
);
7249 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7251 /* These names should be read from the TT name table */
7253 /* length of otmpFamilyName */
7256 /* length of otmpFaceName */
7259 /* length of otmpStyleName */
7262 /* length of otmpFullName */
7266 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7268 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7270 FIXME("Can't find OS/2 table - not TT font?\n");
7274 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7276 FIXME("Can't find HHEA table - not TT font?\n");
7280 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7282 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",
7283 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7284 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7285 pOS2
->xAvgCharWidth
,
7286 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7287 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7288 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7290 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7291 font
->potm
->otmSize
= needed
;
7293 #define TM font->potm->otmTextMetrics
7295 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
7296 ascent
= pHori
->Ascender
;
7297 descent
= -pHori
->Descender
;
7299 ascent
= pOS2
->usWinAscent
;
7300 descent
= pOS2
->usWinDescent
;
7303 font
->ntmCellHeight
= ascent
+ descent
;
7304 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7306 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7307 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7310 TM
.tmAscent
= font
->yMax
;
7311 TM
.tmDescent
= -font
->yMin
;
7312 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7314 TM
.tmAscent
= SCALE_Y(ascent
);
7315 TM
.tmDescent
= SCALE_Y(descent
);
7316 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7319 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7322 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7324 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7325 ((ascent
+ descent
) -
7326 (pHori
->Ascender
- pHori
->Descender
))));
7328 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7329 if (TM
.tmAveCharWidth
== 0) {
7330 TM
.tmAveCharWidth
= 1;
7332 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7333 TM
.tmWeight
= FW_REGULAR
;
7334 if (font
->fake_bold
)
7335 TM
.tmWeight
= FW_BOLD
;
7338 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7340 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7341 TM
.tmWeight
= pOS2
->usWeightClass
;
7343 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7344 TM
.tmWeight
= pOS2
->usWeightClass
;
7347 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7348 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7349 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7350 * symbol range to 0 - f0ff
7353 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7358 case 1257: /* Baltic */
7359 TM
.tmLastChar
= 0xf8fd;
7362 TM
.tmLastChar
= 0xf0ff;
7364 TM
.tmBreakChar
= 0x20;
7365 TM
.tmDefaultChar
= 0x1f;
7369 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7370 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7372 if(pOS2
->usFirstCharIndex
<= 1)
7373 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7374 else if (pOS2
->usFirstCharIndex
> 0xff)
7375 TM
.tmBreakChar
= 0x20;
7377 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7378 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7380 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7381 TM
.tmUnderlined
= font
->underline
;
7382 TM
.tmStruckOut
= font
->strikeout
;
7384 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7385 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7386 (pOS2
->version
== 0xFFFFU
||
7387 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7388 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7390 TM
.tmPitchAndFamily
= 0;
7392 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7394 case PAN_FAMILY_SCRIPT
:
7395 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7398 case PAN_FAMILY_DECORATIVE
:
7399 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7404 case PAN_FAMILY_TEXT_DISPLAY
:
7405 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7406 /* which is clearly not what the panose spec says. */
7408 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7409 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7410 TM
.tmPitchAndFamily
= FF_MODERN
;
7413 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7418 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7421 case PAN_SERIF_COVE
:
7422 case PAN_SERIF_OBTUSE_COVE
:
7423 case PAN_SERIF_SQUARE_COVE
:
7424 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7425 case PAN_SERIF_SQUARE
:
7426 case PAN_SERIF_THIN
:
7427 case PAN_SERIF_BONE
:
7428 case PAN_SERIF_EXAGGERATED
:
7429 case PAN_SERIF_TRIANGLE
:
7430 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7433 case PAN_SERIF_NORMAL_SANS
:
7434 case PAN_SERIF_OBTUSE_SANS
:
7435 case PAN_SERIF_PERP_SANS
:
7436 case PAN_SERIF_FLARED
:
7437 case PAN_SERIF_ROUNDED
:
7438 TM
.tmPitchAndFamily
|= FF_SWISS
;
7445 if(FT_IS_SCALABLE(ft_face
))
7446 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7448 if(FT_IS_SFNT(ft_face
))
7450 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7451 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7453 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7456 TM
.tmCharSet
= font
->charset
;
7458 font
->potm
->otmFiller
= 0;
7459 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7460 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7461 font
->potm
->otmfsType
= pOS2
->fsType
;
7462 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7463 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7464 font
->potm
->otmItalicAngle
= 0; /* POST table */
7465 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7466 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7467 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7468 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7469 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7470 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7471 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7472 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7473 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7474 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7475 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7476 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7477 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7478 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7479 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7480 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7481 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7482 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7483 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7484 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7485 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7486 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7487 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7488 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7490 font
->potm
->otmsUnderscoreSize
= 0;
7491 font
->potm
->otmsUnderscorePosition
= 0;
7493 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7494 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7500 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7501 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7502 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7503 strcpyW((WCHAR
*)cp
, family_nameW
);
7505 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7506 strcpyW((WCHAR
*)cp
, style_nameW
);
7508 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7509 strcpyW((WCHAR
*)cp
, face_nameW
);
7511 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7512 strcpyW((WCHAR
*)cp
, full_nameW
);
7516 HeapFree(GetProcessHeap(), 0, style_nameW
);
7517 HeapFree(GetProcessHeap(), 0, family_nameW
);
7518 HeapFree(GetProcessHeap(), 0, face_nameW
);
7519 HeapFree(GetProcessHeap(), 0, full_nameW
);
7523 /*************************************************************
7524 * freetype_GetGlyphOutline
7526 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7527 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7529 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7535 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7536 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7540 EnterCriticalSection( &freetype_cs
);
7541 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7542 LeaveCriticalSection( &freetype_cs
);
7546 /*************************************************************
7547 * freetype_GetTextMetrics
7549 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7551 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7556 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7557 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7561 EnterCriticalSection( &freetype_cs
);
7562 ret
= get_text_metrics( physdev
->font
, metrics
);
7563 LeaveCriticalSection( &freetype_cs
);
7567 /*************************************************************
7568 * freetype_GetOutlineTextMetrics
7570 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7572 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7577 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7578 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7581 TRACE("font=%p\n", physdev
->font
);
7583 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7586 EnterCriticalSection( &freetype_cs
);
7588 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7590 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7592 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7593 scale_outline_font_metrics(physdev
->font
, potm
);
7595 ret
= physdev
->font
->potm
->otmSize
;
7597 LeaveCriticalSection( &freetype_cs
);
7601 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7603 child
->font
= alloc_font();
7604 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7605 if(!child
->font
->ft_face
)
7607 free_font(child
->font
);
7612 child
->font
->font_desc
= font
->font_desc
;
7613 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7614 child
->font
->orientation
= font
->orientation
;
7615 child
->font
->scale_y
= font
->scale_y
;
7616 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7617 child
->font
->base_font
= font
;
7618 TRACE("created child font %p for base %p\n", child
->font
, font
);
7622 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
7625 CHILD_FONT
*child_font
;
7628 font
= font
->base_font
;
7630 *linked_font
= font
;
7632 if((*glyph
= get_glyph_index(font
, c
)))
7635 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7636 *vert
= (o
!= *glyph
);
7640 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
7642 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7644 if(!child_font
->font
)
7645 if(!load_child_font(font
, child_font
))
7648 if(!child_font
->font
->ft_face
)
7650 g
= get_glyph_index(child_font
->font
, c
);
7652 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7656 *linked_font
= child_font
->font
;
7667 /*************************************************************
7668 * freetype_GetCharWidth
7670 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7672 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7676 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7680 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7681 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7684 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7687 EnterCriticalSection( &freetype_cs
);
7688 for(c
= firstChar
; c
<= lastChar
; c
++) {
7689 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7690 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7692 LeaveCriticalSection( &freetype_cs
);
7696 /*************************************************************
7697 * freetype_GetCharABCWidths
7699 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7701 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7704 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7708 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7709 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7712 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7715 EnterCriticalSection( &freetype_cs
);
7717 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7718 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7720 LeaveCriticalSection( &freetype_cs
);
7724 /*************************************************************
7725 * freetype_GetCharABCWidthsI
7727 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7729 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7732 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7736 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7737 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7740 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7744 EnterCriticalSection( &freetype_cs
);
7746 for(c
= 0; c
< count
; c
++, buffer
++)
7747 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7748 &gm
, buffer
, 0, NULL
, &identity
);
7750 LeaveCriticalSection( &freetype_cs
);
7754 /*************************************************************
7755 * freetype_GetTextExtentExPoint
7757 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7759 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7763 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7767 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7768 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7771 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7774 EnterCriticalSection( &freetype_cs
);
7776 for (idx
= pos
= 0; idx
< count
; idx
++)
7778 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7779 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7783 LeaveCriticalSection( &freetype_cs
);
7787 /*************************************************************
7788 * freetype_GetTextExtentExPointI
7790 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7792 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7796 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7800 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7801 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7804 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7807 EnterCriticalSection( &freetype_cs
);
7809 for (idx
= pos
= 0; idx
< count
; idx
++)
7811 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7812 &gm
, &abc
, 0, NULL
, &identity
);
7813 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7817 LeaveCriticalSection( &freetype_cs
);
7821 /*************************************************************
7822 * freetype_GetFontData
7824 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7826 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7830 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7831 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7834 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7835 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7836 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7838 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7841 /*************************************************************
7842 * freetype_GetTextFace
7844 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7847 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7851 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7852 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7855 n
= strlenW(physdev
->font
->name
) + 1;
7858 lstrcpynW(str
, physdev
->font
->name
, count
);
7864 /*************************************************************
7865 * freetype_GetTextCharsetInfo
7867 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7869 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7873 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7874 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7876 if (fs
) *fs
= physdev
->font
->fs
;
7877 return physdev
->font
->charset
;
7880 /* Retrieve a list of supported Unicode ranges for a given font.
7881 * Can be called with NULL gs to calculate the buffer size. Returns
7882 * the number of ranges found.
7884 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7886 DWORD num_ranges
= 0;
7888 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7891 FT_ULong char_code
, char_code_prev
;
7894 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7896 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7897 face
->num_glyphs
, glyph_code
, char_code
);
7899 if (!glyph_code
) return 0;
7903 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7904 gs
->ranges
[0].cGlyphs
= 0;
7905 gs
->cGlyphsSupported
= 0;
7911 if (char_code
< char_code_prev
)
7913 ERR("expected increasing char code from FT_Get_Next_Char\n");
7916 if (char_code
- char_code_prev
> 1)
7921 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7922 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7923 gs
->cGlyphsSupported
++;
7928 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7929 gs
->cGlyphsSupported
++;
7931 char_code_prev
= char_code
;
7932 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7936 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7941 /*************************************************************
7942 * freetype_GetFontUnicodeRanges
7944 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7946 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7947 DWORD size
, num_ranges
;
7951 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7952 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7955 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7956 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7959 glyphset
->cbThis
= size
;
7960 glyphset
->cRanges
= num_ranges
;
7961 glyphset
->flAccel
= 0;
7966 /*************************************************************
7967 * freetype_FontIsLinked
7969 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7971 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7976 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7977 return dev
->funcs
->pFontIsLinked( dev
);
7981 EnterCriticalSection( &freetype_cs
);
7982 ret
= !list_empty(&physdev
->font
->child_fonts
);
7983 LeaveCriticalSection( &freetype_cs
);
7987 /*************************************************************************
7988 * GetRasterizerCaps (GDI32.@)
7990 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7992 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7993 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7994 lprs
->nLanguageID
= 0;
7998 /*************************************************************
7999 * freetype_GdiRealizationInfo
8001 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
8003 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8004 realization_info_t
*info
= ptr
;
8008 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
8009 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
8012 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
8015 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8018 info
->cache_num
= physdev
->font
->cache_num
;
8019 info
->unknown2
= -1;
8023 /*************************************************************************
8024 * Kerning support for TrueType fonts
8026 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8028 struct TT_kern_table
8034 struct TT_kern_subtable
8043 USHORT horizontal
: 1;
8045 USHORT cross_stream
: 1;
8046 USHORT override
: 1;
8047 USHORT reserved1
: 4;
8053 struct TT_format0_kern_subtable
8057 USHORT entrySelector
;
8068 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8069 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8070 const USHORT
*glyph_to_char
,
8071 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8074 const struct TT_kern_pair
*tt_kern_pair
;
8076 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8078 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8080 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8081 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8082 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8084 if (!kern_pair
|| !cPairs
)
8087 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8089 nPairs
= min(nPairs
, cPairs
);
8091 for (i
= 0; i
< nPairs
; i
++)
8093 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8094 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8095 /* this algorithm appears to better match what Windows does */
8096 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8097 if (kern_pair
->iKernAmount
< 0)
8099 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8100 kern_pair
->iKernAmount
-= font
->ppem
;
8102 else if (kern_pair
->iKernAmount
> 0)
8104 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8105 kern_pair
->iKernAmount
+= font
->ppem
;
8107 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8109 TRACE("left %u right %u value %d\n",
8110 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8114 TRACE("copied %u entries\n", nPairs
);
8118 /*************************************************************
8119 * freetype_GetKerningPairs
8121 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8125 const struct TT_kern_table
*tt_kern_table
;
8126 const struct TT_kern_subtable
*tt_kern_subtable
;
8128 USHORT
*glyph_to_char
;
8130 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8132 if (!(font
= physdev
->font
))
8134 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8135 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8139 EnterCriticalSection( &freetype_cs
);
8140 if (font
->total_kern_pairs
!= (DWORD
)-1)
8142 if (cPairs
&& kern_pair
)
8144 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8145 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8147 else cPairs
= font
->total_kern_pairs
;
8149 LeaveCriticalSection( &freetype_cs
);
8153 font
->total_kern_pairs
= 0;
8155 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8157 if (length
== GDI_ERROR
)
8159 TRACE("no kerning data in the font\n");
8160 LeaveCriticalSection( &freetype_cs
);
8164 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8167 WARN("Out of memory\n");
8168 LeaveCriticalSection( &freetype_cs
);
8172 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8174 /* build a glyph index to char code map */
8175 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8178 WARN("Out of memory allocating a glyph index to char code map\n");
8179 HeapFree(GetProcessHeap(), 0, buf
);
8180 LeaveCriticalSection( &freetype_cs
);
8184 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8190 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8192 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8193 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8197 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8199 /* FIXME: This doesn't match what Windows does: it does some fancy
8200 * things with duplicate glyph index to char code mappings, while
8201 * we just avoid overriding existing entries.
8203 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8204 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8206 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8213 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8214 for (n
= 0; n
<= 65535; n
++)
8215 glyph_to_char
[n
] = (USHORT
)n
;
8218 tt_kern_table
= buf
;
8219 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8220 TRACE("version %u, nTables %u\n",
8221 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8223 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8225 for (i
= 0; i
< nTables
; i
++)
8227 struct TT_kern_subtable tt_kern_subtable_copy
;
8229 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8230 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8231 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8233 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8234 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8235 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8237 /* According to the TrueType specification this is the only format
8238 * that will be properly interpreted by Windows and OS/2
8240 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8242 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8244 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8245 glyph_to_char
, NULL
, 0);
8246 font
->total_kern_pairs
+= new_chunk
;
8248 if (!font
->kern_pairs
)
8249 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8250 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8252 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8253 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8255 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8256 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8259 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8261 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8264 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8265 HeapFree(GetProcessHeap(), 0, buf
);
8267 if (cPairs
&& kern_pair
)
8269 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8270 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8272 else cPairs
= font
->total_kern_pairs
;
8274 LeaveCriticalSection( &freetype_cs
);
8278 static const struct gdi_dc_funcs freetype_funcs
=
8280 NULL
, /* pAbortDoc */
8281 NULL
, /* pAbortPath */
8282 NULL
, /* pAlphaBlend */
8283 NULL
, /* pAngleArc */
8286 NULL
, /* pBeginPath */
8287 NULL
, /* pBlendImage */
8289 NULL
, /* pCloseFigure */
8290 NULL
, /* pCreateCompatibleDC */
8291 freetype_CreateDC
, /* pCreateDC */
8292 freetype_DeleteDC
, /* pDeleteDC */
8293 NULL
, /* pDeleteObject */
8294 NULL
, /* pDeviceCapabilities */
8295 NULL
, /* pEllipse */
8297 NULL
, /* pEndPage */
8298 NULL
, /* pEndPath */
8299 freetype_EnumFonts
, /* pEnumFonts */
8300 NULL
, /* pEnumICMProfiles */
8301 NULL
, /* pExcludeClipRect */
8302 NULL
, /* pExtDeviceMode */
8303 NULL
, /* pExtEscape */
8304 NULL
, /* pExtFloodFill */
8305 NULL
, /* pExtSelectClipRgn */
8306 NULL
, /* pExtTextOut */
8307 NULL
, /* pFillPath */
8308 NULL
, /* pFillRgn */
8309 NULL
, /* pFlattenPath */
8310 freetype_FontIsLinked
, /* pFontIsLinked */
8311 NULL
, /* pFrameRgn */
8312 NULL
, /* pGdiComment */
8313 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
8314 NULL
, /* pGetBoundsRect */
8315 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8316 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8317 freetype_GetCharWidth
, /* pGetCharWidth */
8318 NULL
, /* pGetDeviceCaps */
8319 NULL
, /* pGetDeviceGammaRamp */
8320 freetype_GetFontData
, /* pGetFontData */
8321 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8322 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8323 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8324 NULL
, /* pGetICMProfile */
8325 NULL
, /* pGetImage */
8326 freetype_GetKerningPairs
, /* pGetKerningPairs */
8327 NULL
, /* pGetNearestColor */
8328 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8329 NULL
, /* pGetPixel */
8330 NULL
, /* pGetSystemPaletteEntries */
8331 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8332 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8333 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8334 freetype_GetTextFace
, /* pGetTextFace */
8335 freetype_GetTextMetrics
, /* pGetTextMetrics */
8336 NULL
, /* pGradientFill */
8337 NULL
, /* pIntersectClipRect */
8338 NULL
, /* pInvertRgn */
8340 NULL
, /* pModifyWorldTransform */
8342 NULL
, /* pOffsetClipRgn */
8343 NULL
, /* pOffsetViewportOrg */
8344 NULL
, /* pOffsetWindowOrg */
8345 NULL
, /* pPaintRgn */
8348 NULL
, /* pPolyBezier */
8349 NULL
, /* pPolyBezierTo */
8350 NULL
, /* pPolyDraw */
8351 NULL
, /* pPolyPolygon */
8352 NULL
, /* pPolyPolyline */
8353 NULL
, /* pPolygon */
8354 NULL
, /* pPolyline */
8355 NULL
, /* pPolylineTo */
8356 NULL
, /* pPutImage */
8357 NULL
, /* pRealizeDefaultPalette */
8358 NULL
, /* pRealizePalette */
8359 NULL
, /* pRectangle */
8360 NULL
, /* pResetDC */
8361 NULL
, /* pRestoreDC */
8362 NULL
, /* pRoundRect */
8364 NULL
, /* pScaleViewportExt */
8365 NULL
, /* pScaleWindowExt */
8366 NULL
, /* pSelectBitmap */
8367 NULL
, /* pSelectBrush */
8368 NULL
, /* pSelectClipPath */
8369 freetype_SelectFont
, /* pSelectFont */
8370 NULL
, /* pSelectPalette */
8371 NULL
, /* pSelectPen */
8372 NULL
, /* pSetArcDirection */
8373 NULL
, /* pSetBkColor */
8374 NULL
, /* pSetBkMode */
8375 NULL
, /* pSetDCBrushColor */
8376 NULL
, /* pSetDCPenColor */
8377 NULL
, /* pSetDIBColorTable */
8378 NULL
, /* pSetDIBitsToDevice */
8379 NULL
, /* pSetDeviceClipping */
8380 NULL
, /* pSetDeviceGammaRamp */
8381 NULL
, /* pSetLayout */
8382 NULL
, /* pSetMapMode */
8383 NULL
, /* pSetMapperFlags */
8384 NULL
, /* pSetPixel */
8385 NULL
, /* pSetPolyFillMode */
8386 NULL
, /* pSetROP2 */
8387 NULL
, /* pSetRelAbs */
8388 NULL
, /* pSetStretchBltMode */
8389 NULL
, /* pSetTextAlign */
8390 NULL
, /* pSetTextCharacterExtra */
8391 NULL
, /* pSetTextColor */
8392 NULL
, /* pSetTextJustification */
8393 NULL
, /* pSetViewportExt */
8394 NULL
, /* pSetViewportOrg */
8395 NULL
, /* pSetWindowExt */
8396 NULL
, /* pSetWindowOrg */
8397 NULL
, /* pSetWorldTransform */
8398 NULL
, /* pStartDoc */
8399 NULL
, /* pStartPage */
8400 NULL
, /* pStretchBlt */
8401 NULL
, /* pStretchDIBits */
8402 NULL
, /* pStrokeAndFillPath */
8403 NULL
, /* pStrokePath */
8404 NULL
, /* pUnrealizePalette */
8405 NULL
, /* pWidenPath */
8406 NULL
, /* wine_get_wgl_driver */
8407 GDI_PRIORITY_FONT_DRV
/* priority */
8410 #else /* HAVE_FREETYPE */
8412 /*************************************************************************/
8414 BOOL
WineEngInit(void)
8419 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8421 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8425 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8427 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8431 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8433 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8437 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8438 LPCWSTR font_file
, LPCWSTR font_path
)
8444 /*************************************************************************
8445 * GetRasterizerCaps (GDI32.@)
8447 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8449 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8451 lprs
->nLanguageID
= 0;
8455 #endif /* HAVE_FREETYPE */