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
.bCharSet
) continue;
4517 if((ratio
.xRatio
== 0 &&
4518 ratio
.yStartRatio
== 0 &&
4519 ratio
.yEndRatio
== 0) ||
4520 (devXRatio
== ratio
.xRatio
&&
4521 devYRatio
>= ratio
.yStartRatio
&&
4522 devYRatio
<= ratio
.yEndRatio
))
4524 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4525 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4526 offset
= GET_BE_WORD(tmp
);
4531 if(offset
== -1) return 0;
4533 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4535 BYTE startsz
, endsz
;
4538 recs
= GET_BE_WORD(group
.recs
);
4539 startsz
= group
.startsz
;
4540 endsz
= group
.endsz
;
4542 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4544 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4545 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4546 if(result
== GDI_ERROR
) {
4547 FIXME("Failed to retrieve vTable\n");
4552 for(i
= 0; i
< recs
; i
++) {
4553 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4554 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4555 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4557 if(yMax
+ -yMin
== height
) {
4560 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4563 if(yMax
+ -yMin
> height
) {
4566 goto end
; /* failed */
4568 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4569 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4570 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4571 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4577 TRACE("ppem not found for height %d\n", height
);
4581 if(ppem
< startsz
|| ppem
> endsz
)
4587 for(i
= 0; i
< recs
; i
++) {
4589 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4591 if(yPelHeight
> ppem
)
4597 if(yPelHeight
== ppem
) {
4598 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4599 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4600 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4606 HeapFree(GetProcessHeap(), 0, vTable
);
4612 static void dump_gdi_font_list(void)
4616 TRACE("---------- Font Cache ----------\n");
4617 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4618 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4619 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4622 static void grab_font( GdiFont
*font
)
4624 if (!font
->refcount
++)
4626 list_remove( &font
->unused_entry
);
4627 unused_font_count
--;
4631 static void release_font( GdiFont
*font
)
4634 if (!--font
->refcount
)
4636 TRACE( "font %p\n", font
);
4638 /* add it to the unused list */
4639 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4640 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4642 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4643 TRACE( "freeing %p\n", font
);
4644 list_remove( &font
->entry
);
4645 list_remove( &font
->unused_entry
);
4648 else unused_font_count
++;
4650 if (TRACE_ON(font
)) dump_gdi_font_list();
4654 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4656 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4657 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4658 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4659 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4660 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4663 static void calc_hash(FONT_DESC
*pfd
)
4665 DWORD hash
= 0, *ptr
, two_chars
;
4669 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4671 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4673 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4675 pwc
= (WCHAR
*)&two_chars
;
4677 *pwc
= toupperW(*pwc
);
4679 *pwc
= toupperW(*pwc
);
4683 hash
^= !pfd
->can_use_bitmap
;
4688 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4695 fd
.can_use_bitmap
= can_use_bitmap
;
4698 /* try the in-use list */
4699 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4701 if(fontcmp(ret
, &fd
)) continue;
4702 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4703 list_remove( &ret
->entry
);
4704 list_add_head( &gdi_font_list
, &ret
->entry
);
4711 static void add_to_cache(GdiFont
*font
)
4713 static DWORD cache_num
= 1;
4715 font
->cache_num
= cache_num
++;
4716 list_add_head(&gdi_font_list
, &font
->entry
);
4717 TRACE( "font %p\n", font
);
4720 /*************************************************************
4721 * create_child_font_list
4723 static BOOL
create_child_font_list(GdiFont
*font
)
4726 SYSTEM_LINKS
*font_link
;
4727 CHILD_FONT
*font_link_entry
, *new_child
;
4731 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4732 font_name
= psub
? psub
->to
.name
: font
->name
;
4733 font_link
= find_font_link(font_name
);
4734 if (font_link
!= NULL
)
4736 TRACE("found entry in system list\n");
4737 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4739 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4740 new_child
->face
= font_link_entry
->face
;
4741 new_child
->font
= NULL
;
4742 new_child
->face
->refcount
++;
4743 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4744 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4749 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4750 * Sans Serif. This is how asian windows get default fallbacks for fonts
4752 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4753 font
->charset
!= OEM_CHARSET
&&
4754 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4756 font_link
= find_font_link(szDefaultFallbackLink
);
4757 if (font_link
!= NULL
)
4759 TRACE("found entry in default fallback list\n");
4760 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4762 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4763 new_child
->face
= font_link_entry
->face
;
4764 new_child
->font
= NULL
;
4765 new_child
->face
->refcount
++;
4766 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4767 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4776 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4778 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4780 if (pFT_Set_Charmap
)
4783 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4785 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4787 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4789 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4791 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4792 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4794 switch (ft_face
->charmaps
[i
]->platform_id
)
4797 cmap_def
= ft_face
->charmaps
[i
];
4799 case 0: /* Apple Unicode */
4800 cmap0
= ft_face
->charmaps
[i
];
4802 case 1: /* Macintosh */
4803 cmap1
= ft_face
->charmaps
[i
];
4806 cmap2
= ft_face
->charmaps
[i
];
4808 case 3: /* Microsoft */
4809 cmap3
= ft_face
->charmaps
[i
];
4814 if (cmap3
) /* prefer Microsoft cmap table */
4815 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4817 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4819 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4821 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4823 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4825 return ft_err
== FT_Err_Ok
;
4828 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4832 /*************************************************************
4835 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4836 LPCWSTR output
, const DEVMODEW
*devmode
)
4838 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4840 if (!physdev
) return FALSE
;
4841 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4846 /*************************************************************
4849 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4851 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4852 release_font( physdev
->font
);
4853 HeapFree( GetProcessHeap(), 0, physdev
);
4857 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4859 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4860 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4861 const FT_Encoding
*encs
= regular_order
;
4863 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4867 if (select_charmap( face
, *encs
)) break;
4873 #define GASP_GRIDFIT 0x01
4874 #define GASP_DOGRAY 0x02
4875 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4877 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4880 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4881 WORD
*alloced
= NULL
, *ptr
= buf
;
4882 WORD num_recs
, version
;
4886 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4887 if (size
== GDI_ERROR
) return FALSE
;
4888 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4889 if (size
> sizeof(buf
))
4891 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4892 if (!ptr
) return FALSE
;
4895 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4897 version
= GET_BE_WORD( *ptr
++ );
4898 num_recs
= GET_BE_WORD( *ptr
++ );
4900 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4902 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4908 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4909 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4912 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4916 HeapFree( GetProcessHeap(), 0, alloced
);
4920 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4922 const GSUB_ScriptList
*script
;
4923 const GSUB_Script
*deflt
= NULL
;
4925 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4927 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4928 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4930 const GSUB_Script
*scr
;
4933 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4934 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4936 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4938 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4944 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4948 const GSUB_LangSys
*Lang
;
4950 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4952 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4954 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4955 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4957 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4960 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4963 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4969 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4972 const GSUB_FeatureList
*feature
;
4973 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4975 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4976 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4978 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4979 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4981 const GSUB_Feature
*feat
;
4982 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4989 static const char* get_opentype_script(const GdiFont
*font
)
4992 * I am not sure if this is the correct way to generate our script tag
4995 switch (font
->charset
)
4997 case ANSI_CHARSET
: return "latn";
4998 case BALTIC_CHARSET
: return "latn"; /* ?? */
4999 case CHINESEBIG5_CHARSET
: return "hani";
5000 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5001 case GB2312_CHARSET
: return "hani";
5002 case GREEK_CHARSET
: return "grek";
5003 case HANGUL_CHARSET
: return "hang";
5004 case RUSSIAN_CHARSET
: return "cyrl";
5005 case SHIFTJIS_CHARSET
: return "kana";
5006 case TURKISH_CHARSET
: return "latn"; /* ?? */
5007 case VIETNAMESE_CHARSET
: return "latn";
5008 case JOHAB_CHARSET
: return "latn"; /* ?? */
5009 case ARABIC_CHARSET
: return "arab";
5010 case HEBREW_CHARSET
: return "hebr";
5011 case THAI_CHARSET
: return "thai";
5012 default: return "latn";
5016 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
5018 const GSUB_Header
*header
;
5019 const GSUB_Script
*script
;
5020 const GSUB_LangSys
*language
;
5021 const GSUB_Feature
*feature
;
5023 if (!font
->GSUB_Table
)
5026 header
= font
->GSUB_Table
;
5028 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5031 TRACE("Script not found\n");
5034 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5037 TRACE("Language not found\n");
5040 feature
= GSUB_get_feature(header
, language
, "vrt2");
5042 feature
= GSUB_get_feature(header
, language
, "vert");
5045 TRACE("vrt2/vert feature not found\n");
5051 /*************************************************************
5052 * freetype_SelectFont
5054 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5056 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5058 Face
*face
, *best
, *best_bitmap
;
5059 Family
*family
, *last_resort_family
;
5060 const struct list
*face_list
;
5061 INT height
, width
= 0;
5062 unsigned int score
= 0, new_score
;
5063 signed int diff
= 0, newdiff
;
5064 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5068 FontSubst
*psub
= NULL
;
5069 DC
*dc
= get_dc_ptr( dev
->hdc
);
5070 const SYSTEM_LINKS
*font_link
;
5072 if (!hfont
) /* notification that the font has been changed by another driver */
5074 release_font( physdev
->font
);
5075 physdev
->font
= NULL
;
5076 release_dc_ptr( dc
);
5080 GetObjectW( hfont
, sizeof(lf
), &lf
);
5081 lf
.lfWidth
= abs(lf
.lfWidth
);
5083 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5085 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5086 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5087 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5090 if(dc
->GraphicsMode
== GM_ADVANCED
)
5092 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5093 /* Try to avoid not necessary glyph transformations */
5094 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5096 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5097 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5098 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5103 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5104 font scaling abilities. */
5105 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5106 dcmat
.eM21
= dcmat
.eM12
= 0;
5107 lf
.lfOrientation
= lf
.lfEscapement
;
5108 if (dc
->vport2WorldValid
)
5110 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5111 lf
.lfOrientation
= -lf
.lfOrientation
;
5112 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5113 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5117 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5118 dcmat
.eM21
, dcmat
.eM22
);
5121 EnterCriticalSection( &freetype_cs
);
5123 /* check the cache first */
5124 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5125 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5129 TRACE("not in cache\n");
5132 ret
->font_desc
.matrix
= dcmat
;
5133 ret
->font_desc
.lf
= lf
;
5134 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5135 calc_hash(&ret
->font_desc
);
5137 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5138 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5139 original value lfCharSet. Note this is a special case for
5140 Symbol and doesn't happen at least for "Wingdings*" */
5142 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5143 lf
.lfCharSet
= SYMBOL_CHARSET
;
5145 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5146 switch(lf
.lfCharSet
) {
5147 case DEFAULT_CHARSET
:
5148 csi
.fs
.fsCsb
[0] = 0;
5151 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5152 csi
.fs
.fsCsb
[0] = 0;
5158 if(lf
.lfFaceName
[0] != '\0') {
5159 CHILD_FONT
*font_link_entry
;
5160 LPWSTR FaceName
= lf
.lfFaceName
;
5162 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5165 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5166 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5167 if (psub
->to
.charset
!= -1)
5168 lf
.lfCharSet
= psub
->to
.charset
;
5171 /* We want a match on name and charset or just name if
5172 charset was DEFAULT_CHARSET. If the latter then
5173 we fixup the returned charset later in get_nearest_charset
5174 where we'll either use the charset of the current ansi codepage
5175 or if that's unavailable the first charset that the font supports.
5177 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5178 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5179 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5181 font_link
= find_font_link(family
->FamilyName
);
5182 face_list
= get_face_list_from_family(family
);
5183 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5184 if (!(face
->scalable
|| can_use_bitmap
))
5186 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5188 if (font_link
!= NULL
&&
5189 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5191 if (!csi
.fs
.fsCsb
[0])
5197 /* Search by full face name. */
5198 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5199 face_list
= get_face_list_from_family(family
);
5200 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5201 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5202 (face
->scalable
|| can_use_bitmap
))
5204 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5206 font_link
= find_font_link(family
->FamilyName
);
5207 if (font_link
!= NULL
&&
5208 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5215 * Try check the SystemLink list first for a replacement font.
5216 * We may find good replacements there.
5218 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5220 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5221 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5223 TRACE("found entry in system list\n");
5224 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5226 const SYSTEM_LINKS
*links
;
5228 face
= font_link_entry
->face
;
5229 if (!(face
->scalable
|| can_use_bitmap
))
5231 family
= face
->family
;
5232 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5234 links
= find_font_link(family
->FamilyName
);
5235 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5242 psub
= NULL
; /* substitution is no more relevant */
5244 /* If requested charset was DEFAULT_CHARSET then try using charset
5245 corresponding to the current ansi codepage */
5246 if (!csi
.fs
.fsCsb
[0])
5249 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5250 FIXME("TCI failed on codepage %d\n", acp
);
5251 csi
.fs
.fsCsb
[0] = 0;
5253 lf
.lfCharSet
= csi
.ciCharset
;
5256 want_vertical
= (lf
.lfFaceName
[0] == '@');
5258 /* Face families are in the top 4 bits of lfPitchAndFamily,
5259 so mask with 0xF0 before testing */
5261 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5262 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5263 strcpyW(lf
.lfFaceName
, defFixed
);
5264 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5265 strcpyW(lf
.lfFaceName
, defSerif
);
5266 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5267 strcpyW(lf
.lfFaceName
, defSans
);
5269 strcpyW(lf
.lfFaceName
, defSans
);
5270 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5271 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5272 font_link
= find_font_link(family
->FamilyName
);
5273 face_list
= get_face_list_from_family(family
);
5274 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5275 if (!(face
->scalable
|| can_use_bitmap
))
5277 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5279 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5285 last_resort_family
= NULL
;
5286 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5287 font_link
= find_font_link(family
->FamilyName
);
5288 face_list
= get_face_list_from_family(family
);
5289 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5290 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5291 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5292 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5295 if(can_use_bitmap
&& !last_resort_family
)
5296 last_resort_family
= family
;
5301 if(last_resort_family
) {
5302 family
= last_resort_family
;
5303 csi
.fs
.fsCsb
[0] = 0;
5307 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5308 face_list
= get_face_list_from_family(family
);
5309 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5310 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5311 csi
.fs
.fsCsb
[0] = 0;
5312 WARN("just using first face for now\n");
5315 if(can_use_bitmap
&& !last_resort_family
)
5316 last_resort_family
= family
;
5319 if(!last_resort_family
) {
5320 FIXME("can't find a single appropriate font - bailing\n");
5326 WARN("could only find a bitmap font - this will probably look awful!\n");
5327 family
= last_resort_family
;
5328 csi
.fs
.fsCsb
[0] = 0;
5331 it
= lf
.lfItalic
? 1 : 0;
5332 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5334 height
= lf
.lfHeight
;
5336 face
= best
= best_bitmap
= NULL
;
5337 font_link
= find_font_link(family
->FamilyName
);
5338 face_list
= get_face_list_from_family(family
);
5339 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5341 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5342 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5347 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5348 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5349 new_score
= (italic
^ it
) + (bold
^ bd
);
5350 if(!best
|| new_score
<= score
)
5352 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5353 italic
, bold
, it
, bd
);
5356 if(best
->scalable
&& score
== 0) break;
5360 newdiff
= height
- (signed int)(best
->size
.height
);
5362 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5363 if(!best_bitmap
|| new_score
< score
||
5364 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5366 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5369 if(score
== 0 && diff
== 0) break;
5376 face
= best
->scalable
? best
: best_bitmap
;
5377 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5378 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5381 height
= lf
.lfHeight
;
5385 if(csi
.fs
.fsCsb
[0]) {
5386 ret
->charset
= lf
.lfCharSet
;
5387 ret
->codepage
= csi
.ciACP
;
5390 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5392 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5393 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5395 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5397 if(!face
->scalable
) {
5398 /* Windows uses integer scaling factors for bitmap fonts */
5399 INT scale
, scaled_height
;
5400 GdiFont
*cachedfont
;
5402 /* FIXME: rotation of bitmap fonts is ignored */
5403 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5405 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5406 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5407 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5408 /* As we changed the matrix, we need to search the cache for the font again,
5409 * otherwise we might explode the cache. */
5410 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5411 TRACE("Found cached font after non-scalable matrix rescale!\n");
5416 calc_hash(&ret
->font_desc
);
5418 if (height
!= 0) height
= diff
;
5419 height
+= face
->size
.height
;
5421 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5422 scaled_height
= scale
* face
->size
.height
;
5423 /* Only jump to the next height if the difference <= 25% original height */
5424 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5425 /* The jump between unscaled and doubled is delayed by 1 */
5426 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5427 ret
->scale_y
= scale
;
5429 width
= face
->size
.x_ppem
>> 6;
5430 height
= face
->size
.y_ppem
>> 6;
5434 TRACE("font scale y: %f\n", ret
->scale_y
);
5436 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5445 ret
->ntmFlags
= face
->ntmFlags
;
5447 pick_charmap( ret
->ft_face
, ret
->charset
);
5449 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5450 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5451 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5452 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5453 create_child_font_list(ret
);
5455 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5457 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5458 if (length
!= GDI_ERROR
)
5460 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5461 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5462 TRACE("Loaded GSUB table of %i bytes\n",length
);
5463 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5464 if (!ret
->vert_feature
)
5466 TRACE("Vertical feature not found\n");
5467 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5468 ret
->GSUB_Table
= NULL
;
5472 ret
->aa_flags
= HIWORD( face
->flags
);
5474 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5480 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5482 switch (lf
.lfQuality
)
5484 case NONANTIALIASED_QUALITY
:
5485 case ANTIALIASED_QUALITY
:
5486 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5488 case CLEARTYPE_QUALITY
:
5489 case CLEARTYPE_NATURAL_QUALITY
:
5491 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5492 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5494 /* fixup the antialiasing flags for that font */
5497 case WINE_GGO_HRGB_BITMAP
:
5498 case WINE_GGO_HBGR_BITMAP
:
5499 case WINE_GGO_VRGB_BITMAP
:
5500 case WINE_GGO_VBGR_BITMAP
:
5501 if (is_subpixel_rendering_enabled()) break;
5502 *aa_flags
= GGO_GRAY4_BITMAP
;
5504 case GGO_GRAY2_BITMAP
:
5505 case GGO_GRAY4_BITMAP
:
5506 case GGO_GRAY8_BITMAP
:
5507 case WINE_GGO_GRAY16_BITMAP
:
5508 if (is_hinting_enabled())
5511 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5513 TRACE( "font %s %d aa disabled by GASP\n",
5514 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5515 *aa_flags
= GGO_BITMAP
;
5520 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5521 release_font( physdev
->font
);
5522 physdev
->font
= ret
;
5524 LeaveCriticalSection( &freetype_cs
);
5525 release_dc_ptr( dc
);
5526 return ret
? hfont
: 0;
5529 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5536 id
+= IDS_FIRST_SCRIPT
;
5537 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5538 if (!rsrc
) return 0;
5539 hMem
= LoadResource( gdi32_module
, rsrc
);
5540 if (!hMem
) return 0;
5542 p
= LockResource( hMem
);
5544 while (id
--) p
+= *p
+ 1;
5546 i
= min(LF_FACESIZE
- 1, *p
);
5547 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5553 /***************************************************
5554 * create_enum_charset_list
5556 * This function creates charset enumeration list because in DEFAULT_CHARSET
5557 * case, the ANSI codepage's charset takes precedence over other charsets.
5558 * This function works as a filter other than DEFAULT_CHARSET case.
5560 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5565 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5566 csi
.fs
.fsCsb
[0] != 0) {
5567 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5568 list
->element
[n
].charset
= csi
.ciCharset
;
5569 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5572 else { /* charset is DEFAULT_CHARSET or invalid. */
5576 /* Set the current codepage's charset as the first element. */
5578 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5579 csi
.fs
.fsCsb
[0] != 0) {
5580 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5581 list
->element
[n
].charset
= csi
.ciCharset
;
5582 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5583 mask
|= csi
.fs
.fsCsb
[0];
5587 /* Fill out left elements. */
5588 for (i
= 0; i
< 32; i
++) {
5590 fs
.fsCsb
[0] = 1L << i
;
5592 if (fs
.fsCsb
[0] & mask
)
5593 continue; /* skip, already added. */
5594 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5595 continue; /* skip, this is an invalid fsCsb bit. */
5597 list
->element
[n
].mask
= fs
.fsCsb
[0];
5598 list
->element
[n
].charset
= csi
.ciCharset
;
5599 load_script_name( i
, list
->element
[n
].name
);
5600 mask
|= fs
.fsCsb
[0];
5604 /* add catch all mask for remaining bits */
5607 list
->element
[n
].mask
= ~mask
;
5608 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5609 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5618 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5619 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5624 if (face
->cached_enum_data
)
5627 *pelf
= face
->cached_enum_data
->elf
;
5628 *pntm
= face
->cached_enum_data
->ntm
;
5629 *ptype
= face
->cached_enum_data
->type
;
5633 font
= alloc_font();
5635 if(face
->scalable
) {
5639 height
= face
->size
.y_ppem
>> 6;
5640 width
= face
->size
.x_ppem
>> 6;
5642 font
->scale_y
= 1.0;
5644 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5650 font
->name
= strdupW( family_name
);
5651 font
->ntmFlags
= face
->ntmFlags
;
5653 if (get_outline_text_metrics(font
))
5655 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5657 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5658 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5659 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5661 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5662 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5664 lstrcpynW(pelf
->elfFullName
,
5665 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5667 lstrcpynW(pelf
->elfStyle
,
5668 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5673 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5675 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5676 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5677 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5679 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5681 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5683 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5684 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5687 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5688 pntm
->ntmFontSig
= face
->fs
;
5690 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5692 pelf
->elfLogFont
.lfEscapement
= 0;
5693 pelf
->elfLogFont
.lfOrientation
= 0;
5694 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5695 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5696 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5697 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5698 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5699 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5700 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5701 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5702 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5703 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5704 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5707 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5708 *ptype
|= TRUETYPE_FONTTYPE
;
5709 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5710 *ptype
|= DEVICE_FONTTYPE
;
5711 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5712 *ptype
|= RASTER_FONTTYPE
;
5714 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5715 if (face
->cached_enum_data
)
5717 face
->cached_enum_data
->elf
= *pelf
;
5718 face
->cached_enum_data
->ntm
= *pntm
;
5719 face
->cached_enum_data
->type
= *ptype
;
5725 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5728 const struct list
*face_list
;
5730 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5732 face_list
= get_face_list_from_family(family
);
5733 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5734 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5739 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5741 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5743 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5746 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5747 FONTENUMPROCW proc
, LPARAM lparam
)
5750 NEWTEXTMETRICEXW ntm
;
5754 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5755 for(i
= 0; i
< list
->total
; i
++) {
5756 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5757 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5758 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5759 i
= list
->total
; /* break out of loop after enumeration */
5763 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5764 /* use the DEFAULT_CHARSET case only if no other charset is present */
5765 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5766 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5767 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5768 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5769 if (!elf
.elfScript
[0])
5770 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5772 /* Font Replacement */
5773 if (family
!= face
->family
)
5775 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5777 strcpyW(elf
.elfFullName
, face
->FullName
);
5779 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5781 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5782 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5783 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5784 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5785 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5786 ntm
.ntmTm
.ntmFlags
);
5787 /* release section before callback (FIXME) */
5788 LeaveCriticalSection( &freetype_cs
);
5789 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5790 EnterCriticalSection( &freetype_cs
);
5795 /*************************************************************
5796 * freetype_EnumFonts
5798 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5802 const struct list
*face_list
;
5804 struct enum_charset_list enum_charsets
;
5808 lf
.lfCharSet
= DEFAULT_CHARSET
;
5809 lf
.lfPitchAndFamily
= 0;
5810 lf
.lfFaceName
[0] = 0;
5814 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5816 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5819 EnterCriticalSection( &freetype_cs
);
5820 if(plf
->lfFaceName
[0]) {
5822 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5825 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5826 debugstr_w(psub
->to
.name
));
5828 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5832 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5833 if (!family_matches(family
, plf
)) continue;
5834 face_list
= get_face_list_from_family(family
);
5835 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5836 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5837 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5841 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5842 face_list
= get_face_list_from_family(family
);
5843 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5844 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5847 LeaveCriticalSection( &freetype_cs
);
5851 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5853 pt
->x
.value
= vec
->x
>> 6;
5854 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5855 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5856 pt
->y
.value
= vec
->y
>> 6;
5857 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5858 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5862 /***************************************************
5863 * According to the MSDN documentation on WideCharToMultiByte,
5864 * certain codepages cannot set the default_used parameter.
5865 * This returns TRUE if the codepage can set that parameter, false else
5866 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5868 static BOOL
codepage_sets_default_used(UINT codepage
)
5882 * GSUB Table handling functions
5885 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5887 const GSUB_CoverageFormat1
* cf1
;
5891 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5893 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5895 TRACE("Coverage Format 1, %i glyphs\n",count
);
5896 for (i
= 0; i
< count
; i
++)
5897 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5901 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5903 const GSUB_CoverageFormat2
* cf2
;
5906 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5908 count
= GET_BE_WORD(cf2
->RangeCount
);
5909 TRACE("Coverage Format 2, %i ranges\n",count
);
5910 for (i
= 0; i
< count
; i
++)
5912 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5914 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5915 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5917 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5918 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5924 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5929 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5933 const GSUB_LookupList
*lookup
;
5934 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5936 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5937 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5939 const GSUB_LookupTable
*look
;
5940 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5941 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5942 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5943 if (GET_BE_WORD(look
->LookupType
) != 1)
5944 FIXME("We only handle SubType 1\n");
5949 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5951 const GSUB_SingleSubstFormat1
*ssf1
;
5952 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5953 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5954 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5956 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5957 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5958 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5960 TRACE(" Glyph 0x%x ->",glyph
);
5961 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5962 TRACE(" 0x%x\n",glyph
);
5967 const GSUB_SingleSubstFormat2
*ssf2
;
5971 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5972 offset
= GET_BE_WORD(ssf1
->Coverage
);
5973 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5974 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5975 TRACE(" Coverage index %i\n",index
);
5978 TRACE(" Glyph is 0x%x ->",glyph
);
5979 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5980 TRACE("0x%x\n",glyph
);
5990 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5992 const GSUB_Header
*header
;
5993 const GSUB_Feature
*feature
;
5995 if (!font
->GSUB_Table
)
5998 header
= font
->GSUB_Table
;
5999 feature
= font
->vert_feature
;
6001 return GSUB_apply_feature(header
, feature
, glyph
);
6004 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
6008 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6009 WCHAR wc
= (WCHAR
)glyph
;
6011 BOOL
*default_used_pointer
;
6014 default_used_pointer
= NULL
;
6015 default_used
= FALSE
;
6016 if (codepage_sets_default_used(font
->codepage
))
6017 default_used_pointer
= &default_used
;
6018 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6020 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6021 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6026 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6027 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
6031 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6033 if (glyph
< 0x100) glyph
+= 0xf000;
6034 /* there is a number of old pre-Unicode "broken" TTFs, which
6035 do have symbols at U+00XX instead of U+f0XX */
6036 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6037 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6039 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6044 static FT_UInt
get_default_char_index(GdiFont
*font
)
6046 FT_UInt default_char
;
6048 if (FT_IS_SFNT(font
->ft_face
))
6050 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6051 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6056 get_text_metrics(font
, &textm
);
6057 default_char
= textm
.tmDefaultChar
;
6060 return default_char
;
6063 /*************************************************************
6064 * freetype_GetGlyphIndices
6066 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6068 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6071 BOOL got_default
= FALSE
;
6075 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6076 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6079 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6081 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6086 EnterCriticalSection( &freetype_cs
);
6088 for(i
= 0; i
< count
; i
++)
6090 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
6095 default_char
= get_default_char_index(physdev
->font
);
6098 pgi
[i
] = default_char
;
6101 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6103 LeaveCriticalSection( &freetype_cs
);
6107 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6109 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6110 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6113 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6115 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6116 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6119 static inline BYTE
get_max_level( UINT format
)
6123 case GGO_GRAY2_BITMAP
: return 4;
6124 case GGO_GRAY4_BITMAP
: return 16;
6125 case GGO_GRAY8_BITMAP
: return 64;
6130 static const struct { WCHAR lower
; WCHAR upper
;} unrotate_ranges
[] =
6137 /* General Punctuation */
6139 /* Currency Symbols */
6140 /* Combining Diacritical Marks for Symbols */
6141 /* Letterlike Symbols */
6143 /* Enclosed Alphanumerics */
6145 /* Geometric Shapes */
6146 /* Miscellaneous Symbols */
6148 /* Miscellaneous Mathematical Symbols-A */
6149 /* Supplemental Arrows-A */
6151 /* East Asian scripts and symbols */
6153 /* Hangul Syllables */
6154 /* Hangul Jamo Extended-B */
6156 /* Private Use Area */
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 width
= (right
- left
) >> 6;
6522 height
= (top
- bottom
) >> 6;
6523 lpgm
->gmBlackBoxX
= width
;
6524 lpgm
->gmBlackBoxY
= height
;
6525 lpgm
->gmptGlyphOrigin
.x
= origin_x
>> 6;
6526 lpgm
->gmptGlyphOrigin
.y
= origin_y
>> 6;
6527 abc
->abcA
= left
>> 6;
6529 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6531 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6532 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6533 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6535 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6536 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6538 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6539 FONT_GM(font
,original_index
)->abc
= *abc
;
6540 FONT_GM(font
,original_index
)->init
= TRUE
;
6543 if(format
== GGO_METRICS
)
6545 return 1; /* FIXME */
6548 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6549 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6551 TRACE("loaded a bitmap\n");
6557 pitch
= ((width
+ 31) >> 5) << 2;
6558 needed
= pitch
* height
;
6560 if(!buf
|| !buflen
) break;
6561 if (!needed
) return GDI_ERROR
; /* empty glyph */
6563 switch(ft_face
->glyph
->format
) {
6564 case ft_glyph_format_bitmap
:
6566 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6567 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6568 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6570 memcpy(dst
, src
, w
);
6571 src
+= ft_face
->glyph
->bitmap
.pitch
;
6577 case ft_glyph_format_outline
:
6578 ft_bitmap
.width
= width
;
6579 ft_bitmap
.rows
= height
;
6580 ft_bitmap
.pitch
= pitch
;
6581 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6582 ft_bitmap
.buffer
= buf
;
6585 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6587 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6589 /* Note: FreeType will only set 'black' bits for us. */
6590 memset(buf
, 0, needed
);
6591 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6595 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6600 case GGO_GRAY2_BITMAP
:
6601 case GGO_GRAY4_BITMAP
:
6602 case GGO_GRAY8_BITMAP
:
6603 case WINE_GGO_GRAY16_BITMAP
:
6605 unsigned int max_level
, row
, col
;
6608 pitch
= (width
+ 3) / 4 * 4;
6609 needed
= pitch
* height
;
6611 if(!buf
|| !buflen
) break;
6612 if (!needed
) return GDI_ERROR
; /* empty glyph */
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
:
6681 needed
= pitch
* height
;
6683 if (!buf
|| !buflen
) break;
6684 if (!needed
) return GDI_ERROR
; /* empty glyph */
6686 memset(buf
, 0, buflen
);
6688 src
= ft_face
->glyph
->bitmap
.buffer
;
6689 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6691 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6694 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6696 if ( src
[x
/ 8] & masks
[x
% 8] )
6697 ((unsigned int *)dst
)[x
] = ~0u;
6706 case FT_GLYPH_FORMAT_OUTLINE
:
6710 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6711 INT x_shift
, y_shift
;
6713 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6714 FT_Render_Mode render_mode
=
6715 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6716 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6718 if (!width
|| !height
)
6720 if (!buf
|| !buflen
) return 0;
6724 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6726 if ( render_mode
== FT_RENDER_MODE_LCD
)
6728 lpgm
->gmBlackBoxX
+= 2;
6729 lpgm
->gmptGlyphOrigin
.x
-= 1;
6733 lpgm
->gmBlackBoxY
+= 2;
6734 lpgm
->gmptGlyphOrigin
.y
+= 1;
6738 width
= lpgm
->gmBlackBoxX
;
6739 height
= lpgm
->gmBlackBoxY
;
6741 needed
= pitch
* height
;
6743 if (!buf
|| !buflen
) break;
6745 memset(buf
, 0, buflen
);
6747 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6749 if ( needsTransform
)
6750 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
6752 if ( pFT_Library_SetLcdFilter
)
6753 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6754 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6756 src
= ft_face
->glyph
->bitmap
.buffer
;
6757 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6758 src_width
= ft_face
->glyph
->bitmap
.width
;
6759 src_height
= ft_face
->glyph
->bitmap
.rows
;
6761 if ( render_mode
== FT_RENDER_MODE_LCD
)
6769 rgb_interval
= src_pitch
;
6774 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6777 src
+= hmul
* -x_shift
;
6778 src_width
-= hmul
* -x_shift
;
6780 else if ( x_shift
> 0 )
6786 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6789 src
+= src_pitch
* vmul
* -y_shift
;
6790 src_height
-= vmul
* -y_shift
;
6792 else if ( y_shift
> 0 )
6794 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
6798 width
= min( width
, src_width
/ hmul
);
6799 height
= min( height
, src_height
/ vmul
);
6803 for ( x
= 0; x
< width
; x
++ )
6807 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6808 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6809 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6810 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6814 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6815 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6816 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6817 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6820 src
+= src_pitch
* vmul
;
6821 dst
+= pitch
/ sizeof(*dst
);
6828 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6840 int contour
, point
= 0, first_pt
;
6841 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6842 TTPOLYGONHEADER
*pph
;
6844 DWORD pph_start
, cpfx
, type
;
6846 if(buflen
== 0) buf
= NULL
;
6848 if (needsTransform
&& buf
) {
6849 pFT_Outline_Transform(outline
, &transMatTategaki
);
6852 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6853 /* Ignore contours containing one point */
6854 if(point
== outline
->contours
[contour
]) {
6860 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6863 pph
->dwType
= TT_POLYGON_TYPE
;
6864 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6866 needed
+= sizeof(*pph
);
6868 while(point
<= outline
->contours
[contour
]) {
6869 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6870 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6871 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6875 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6878 } while(point
<= outline
->contours
[contour
] &&
6879 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6880 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6881 /* At the end of a contour Windows adds the start point, but
6883 if(point
> outline
->contours
[contour
] &&
6884 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6886 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6888 } else if(point
<= outline
->contours
[contour
] &&
6889 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6890 /* add closing pt for bezier */
6892 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6900 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6903 pph
->cb
= needed
- pph_start
;
6909 /* Convert the quadratic Beziers to cubic Beziers.
6910 The parametric eqn for a cubic Bezier is, from PLRM:
6911 r(t) = at^3 + bt^2 + ct + r0
6912 with the control points:
6917 A quadratic Bezier has the form:
6918 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6920 So equating powers of t leads to:
6921 r1 = 2/3 p1 + 1/3 p0
6922 r2 = 2/3 p1 + 1/3 p2
6923 and of course r0 = p0, r3 = p2
6926 int contour
, point
= 0, first_pt
;
6927 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6928 TTPOLYGONHEADER
*pph
;
6930 DWORD pph_start
, cpfx
, type
;
6931 FT_Vector cubic_control
[4];
6932 if(buflen
== 0) buf
= NULL
;
6934 if (needsTransform
&& buf
) {
6935 pFT_Outline_Transform(outline
, &transMat
);
6938 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6940 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6943 pph
->dwType
= TT_POLYGON_TYPE
;
6944 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6946 needed
+= sizeof(*pph
);
6948 while(point
<= outline
->contours
[contour
]) {
6949 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6950 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6951 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6954 if(type
== TT_PRIM_LINE
) {
6956 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6960 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6963 /* FIXME: Possible optimization in endpoint calculation
6964 if there are two consecutive curves */
6965 cubic_control
[0] = outline
->points
[point
-1];
6966 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6967 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6968 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6969 cubic_control
[0].x
>>= 1;
6970 cubic_control
[0].y
>>= 1;
6972 if(point
+1 > outline
->contours
[contour
])
6973 cubic_control
[3] = outline
->points
[first_pt
];
6975 cubic_control
[3] = outline
->points
[point
+1];
6976 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6977 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6978 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6979 cubic_control
[3].x
>>= 1;
6980 cubic_control
[3].y
>>= 1;
6983 /* r1 = 1/3 p0 + 2/3 p1
6984 r2 = 1/3 p2 + 2/3 p1 */
6985 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6986 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6987 cubic_control
[2] = cubic_control
[1];
6988 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6989 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6990 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6991 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6993 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6994 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6995 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
7000 } while(point
<= outline
->contours
[contour
] &&
7001 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
7002 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
7003 /* At the end of a contour Windows adds the start point,
7004 but only for Beziers and we've already done that.
7006 if(point
<= outline
->contours
[contour
] &&
7007 outline
->tags
[point
] & FT_Curve_Tag_On
) {
7008 /* This is the closing pt of a bezier, but we've already
7009 added it, so just inc point and carry on */
7016 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
7019 pph
->cb
= needed
- pph_start
;
7025 FIXME("Unsupported format %d\n", format
);
7031 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7033 FT_Face ft_face
= font
->ft_face
;
7034 FT_WinFNT_HeaderRec winfnt_header
;
7035 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7036 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7037 font
->potm
->otmSize
= size
;
7039 #define TM font->potm->otmTextMetrics
7040 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7042 TM
.tmHeight
= winfnt_header
.pixel_height
;
7043 TM
.tmAscent
= winfnt_header
.ascent
;
7044 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7045 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7046 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7047 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7048 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7049 TM
.tmWeight
= winfnt_header
.weight
;
7051 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7052 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7053 TM
.tmFirstChar
= winfnt_header
.first_char
;
7054 TM
.tmLastChar
= winfnt_header
.last_char
;
7055 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7056 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7057 TM
.tmItalic
= winfnt_header
.italic
;
7058 TM
.tmUnderlined
= font
->underline
;
7059 TM
.tmStruckOut
= font
->strikeout
;
7060 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7061 TM
.tmCharSet
= winfnt_header
.charset
;
7065 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7066 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7067 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7068 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7069 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7070 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7071 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7072 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7074 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7075 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7077 TM
.tmLastChar
= 255;
7078 TM
.tmDefaultChar
= 32;
7079 TM
.tmBreakChar
= 32;
7080 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7081 TM
.tmUnderlined
= font
->underline
;
7082 TM
.tmStruckOut
= font
->strikeout
;
7083 /* NB inverted meaning of TMPF_FIXED_PITCH */
7084 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
7085 TM
.tmCharSet
= font
->charset
;
7093 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7095 double scale_x
, scale_y
;
7099 scale_x
= (double)font
->aveWidth
;
7100 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7103 scale_x
= font
->scale_y
;
7105 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7106 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7108 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7109 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7111 SCALE_Y(ptm
->tmHeight
);
7112 SCALE_Y(ptm
->tmAscent
);
7113 SCALE_Y(ptm
->tmDescent
);
7114 SCALE_Y(ptm
->tmInternalLeading
);
7115 SCALE_Y(ptm
->tmExternalLeading
);
7116 SCALE_Y(ptm
->tmOverhang
);
7118 SCALE_X(ptm
->tmAveCharWidth
);
7119 SCALE_X(ptm
->tmMaxCharWidth
);
7125 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7127 double scale_x
, scale_y
;
7131 scale_x
= (double)font
->aveWidth
;
7132 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7135 scale_x
= font
->scale_y
;
7137 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7138 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7140 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7142 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7143 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7145 SCALE_Y(potm
->otmAscent
);
7146 SCALE_Y(potm
->otmDescent
);
7147 SCALE_Y(potm
->otmLineGap
);
7148 SCALE_Y(potm
->otmsCapEmHeight
);
7149 SCALE_Y(potm
->otmsXHeight
);
7150 SCALE_Y(potm
->otmrcFontBox
.top
);
7151 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7152 SCALE_X(potm
->otmrcFontBox
.left
);
7153 SCALE_X(potm
->otmrcFontBox
.right
);
7154 SCALE_Y(potm
->otmMacAscent
);
7155 SCALE_Y(potm
->otmMacDescent
);
7156 SCALE_Y(potm
->otmMacLineGap
);
7157 SCALE_X(potm
->otmptSubscriptSize
.x
);
7158 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7159 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7160 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7161 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7162 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7163 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7164 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7165 SCALE_Y(potm
->otmsStrikeoutSize
);
7166 SCALE_Y(potm
->otmsStrikeoutPosition
);
7167 SCALE_Y(potm
->otmsUnderscoreSize
);
7168 SCALE_Y(potm
->otmsUnderscorePosition
);
7174 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7178 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7180 /* Make sure that the font has sane width/height ratio */
7183 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7185 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7190 *ptm
= font
->potm
->otmTextMetrics
;
7191 scale_font_metrics(font
, ptm
);
7195 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7199 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7201 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7207 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7210 FT_Face ft_face
= font
->ft_face
;
7211 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7213 TT_HoriHeader
*pHori
;
7214 TT_Postscript
*pPost
;
7216 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7218 INT ascent
, descent
;
7220 TRACE("font=%p\n", font
);
7222 if(!FT_IS_SCALABLE(ft_face
))
7225 needed
= sizeof(*font
->potm
);
7227 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7228 family_nameW
= strdupW(font
->name
);
7230 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7233 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7234 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7236 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7238 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7241 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7242 face_nameW
= strdupW(font
->name
);
7244 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7245 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7247 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7250 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7251 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7252 full_nameW
= strdupW(fake_nameW
);
7254 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7256 /* These names should be read from the TT name table */
7258 /* length of otmpFamilyName */
7261 /* length of otmpFaceName */
7264 /* length of otmpStyleName */
7267 /* length of otmpFullName */
7271 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7273 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7275 FIXME("Can't find OS/2 table - not TT font?\n");
7279 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7281 FIXME("Can't find HHEA table - not TT font?\n");
7285 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7287 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",
7288 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7289 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7290 pOS2
->xAvgCharWidth
,
7291 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7292 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7293 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7295 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7296 font
->potm
->otmSize
= needed
;
7298 #define TM font->potm->otmTextMetrics
7300 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
7301 ascent
= pHori
->Ascender
;
7302 descent
= -pHori
->Descender
;
7304 ascent
= pOS2
->usWinAscent
;
7305 descent
= pOS2
->usWinDescent
;
7308 font
->ntmCellHeight
= ascent
+ descent
;
7309 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7311 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7312 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7315 TM
.tmAscent
= font
->yMax
;
7316 TM
.tmDescent
= -font
->yMin
;
7317 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7319 TM
.tmAscent
= SCALE_Y(ascent
);
7320 TM
.tmDescent
= SCALE_Y(descent
);
7321 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7324 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7327 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7329 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7330 ((ascent
+ descent
) -
7331 (pHori
->Ascender
- pHori
->Descender
))));
7333 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7334 if (TM
.tmAveCharWidth
== 0) {
7335 TM
.tmAveCharWidth
= 1;
7337 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7338 TM
.tmWeight
= FW_REGULAR
;
7339 if (font
->fake_bold
)
7340 TM
.tmWeight
= FW_BOLD
;
7343 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7345 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7346 TM
.tmWeight
= pOS2
->usWeightClass
;
7348 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7349 TM
.tmWeight
= pOS2
->usWeightClass
;
7352 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7353 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7354 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7355 * symbol range to 0 - f0ff
7358 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7363 case 1257: /* Baltic */
7364 TM
.tmLastChar
= 0xf8fd;
7367 TM
.tmLastChar
= 0xf0ff;
7369 TM
.tmBreakChar
= 0x20;
7370 TM
.tmDefaultChar
= 0x1f;
7374 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7375 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7377 if(pOS2
->usFirstCharIndex
<= 1)
7378 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7379 else if (pOS2
->usFirstCharIndex
> 0xff)
7380 TM
.tmBreakChar
= 0x20;
7382 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7383 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7385 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7386 TM
.tmUnderlined
= font
->underline
;
7387 TM
.tmStruckOut
= font
->strikeout
;
7389 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7390 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7391 (pOS2
->version
== 0xFFFFU
||
7392 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7393 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7395 TM
.tmPitchAndFamily
= 0;
7397 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7399 case PAN_FAMILY_SCRIPT
:
7400 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7403 case PAN_FAMILY_DECORATIVE
:
7404 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7409 case PAN_FAMILY_TEXT_DISPLAY
:
7410 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7411 /* which is clearly not what the panose spec says. */
7413 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7414 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7415 TM
.tmPitchAndFamily
= FF_MODERN
;
7418 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7423 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7426 case PAN_SERIF_COVE
:
7427 case PAN_SERIF_OBTUSE_COVE
:
7428 case PAN_SERIF_SQUARE_COVE
:
7429 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7430 case PAN_SERIF_SQUARE
:
7431 case PAN_SERIF_THIN
:
7432 case PAN_SERIF_BONE
:
7433 case PAN_SERIF_EXAGGERATED
:
7434 case PAN_SERIF_TRIANGLE
:
7435 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7438 case PAN_SERIF_NORMAL_SANS
:
7439 case PAN_SERIF_OBTUSE_SANS
:
7440 case PAN_SERIF_PERP_SANS
:
7441 case PAN_SERIF_FLARED
:
7442 case PAN_SERIF_ROUNDED
:
7443 TM
.tmPitchAndFamily
|= FF_SWISS
;
7450 if(FT_IS_SCALABLE(ft_face
))
7451 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7453 if(FT_IS_SFNT(ft_face
))
7455 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7456 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7458 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7461 TM
.tmCharSet
= font
->charset
;
7463 font
->potm
->otmFiller
= 0;
7464 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7465 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7466 font
->potm
->otmfsType
= pOS2
->fsType
;
7467 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7468 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7469 font
->potm
->otmItalicAngle
= 0; /* POST table */
7470 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7471 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7472 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7473 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7474 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7475 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7476 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7477 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7478 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7479 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7480 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7481 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7482 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7483 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7484 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7485 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7486 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7487 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7488 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7489 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7490 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7491 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7492 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7493 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7495 font
->potm
->otmsUnderscoreSize
= 0;
7496 font
->potm
->otmsUnderscorePosition
= 0;
7498 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7499 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7505 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7506 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7507 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7508 strcpyW((WCHAR
*)cp
, family_nameW
);
7510 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7511 strcpyW((WCHAR
*)cp
, style_nameW
);
7513 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7514 strcpyW((WCHAR
*)cp
, face_nameW
);
7516 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7517 strcpyW((WCHAR
*)cp
, full_nameW
);
7521 HeapFree(GetProcessHeap(), 0, style_nameW
);
7522 HeapFree(GetProcessHeap(), 0, family_nameW
);
7523 HeapFree(GetProcessHeap(), 0, face_nameW
);
7524 HeapFree(GetProcessHeap(), 0, full_nameW
);
7528 /*************************************************************
7529 * freetype_GetGlyphOutline
7531 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7532 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7534 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7540 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7541 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7545 EnterCriticalSection( &freetype_cs
);
7546 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7547 LeaveCriticalSection( &freetype_cs
);
7551 /*************************************************************
7552 * freetype_GetTextMetrics
7554 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7556 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7561 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7562 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7566 EnterCriticalSection( &freetype_cs
);
7567 ret
= get_text_metrics( physdev
->font
, metrics
);
7568 LeaveCriticalSection( &freetype_cs
);
7572 /*************************************************************
7573 * freetype_GetOutlineTextMetrics
7575 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7577 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7582 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7583 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7586 TRACE("font=%p\n", physdev
->font
);
7588 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7591 EnterCriticalSection( &freetype_cs
);
7593 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7595 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7597 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7598 scale_outline_font_metrics(physdev
->font
, potm
);
7600 ret
= physdev
->font
->potm
->otmSize
;
7602 LeaveCriticalSection( &freetype_cs
);
7606 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7608 child
->font
= alloc_font();
7609 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7610 if(!child
->font
->ft_face
)
7612 free_font(child
->font
);
7617 child
->font
->font_desc
= font
->font_desc
;
7618 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7619 child
->font
->orientation
= font
->orientation
;
7620 child
->font
->scale_y
= font
->scale_y
;
7621 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7622 child
->font
->base_font
= font
;
7623 TRACE("created child font %p for base %p\n", child
->font
, font
);
7627 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
7630 CHILD_FONT
*child_font
;
7633 font
= font
->base_font
;
7635 *linked_font
= font
;
7637 if((*glyph
= get_glyph_index(font
, c
)))
7640 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7641 *vert
= (o
!= *glyph
);
7645 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
7647 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7649 if(!child_font
->font
)
7650 if(!load_child_font(font
, child_font
))
7653 if(!child_font
->font
->ft_face
)
7655 g
= get_glyph_index(child_font
->font
, c
);
7657 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7661 *linked_font
= child_font
->font
;
7672 /*************************************************************
7673 * freetype_GetCharWidth
7675 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7677 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7681 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7685 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7686 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7689 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7692 EnterCriticalSection( &freetype_cs
);
7693 for(c
= firstChar
; c
<= lastChar
; c
++) {
7694 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7695 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7697 LeaveCriticalSection( &freetype_cs
);
7701 /*************************************************************
7702 * freetype_GetCharABCWidths
7704 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7706 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7709 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7713 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7714 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7717 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7720 EnterCriticalSection( &freetype_cs
);
7722 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7723 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7725 LeaveCriticalSection( &freetype_cs
);
7729 /*************************************************************
7730 * freetype_GetCharABCWidthsI
7732 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7734 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7737 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7741 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7742 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7745 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7749 EnterCriticalSection( &freetype_cs
);
7751 for(c
= 0; c
< count
; c
++, buffer
++)
7752 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7753 &gm
, buffer
, 0, NULL
, &identity
);
7755 LeaveCriticalSection( &freetype_cs
);
7759 /*************************************************************
7760 * freetype_GetTextExtentExPoint
7762 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7764 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7768 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7772 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7773 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7776 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7779 EnterCriticalSection( &freetype_cs
);
7781 for (idx
= pos
= 0; idx
< count
; idx
++)
7783 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7784 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7788 LeaveCriticalSection( &freetype_cs
);
7792 /*************************************************************
7793 * freetype_GetTextExtentExPointI
7795 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7797 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7801 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7805 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7806 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7809 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7812 EnterCriticalSection( &freetype_cs
);
7814 for (idx
= pos
= 0; idx
< count
; idx
++)
7816 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7817 &gm
, &abc
, 0, NULL
, &identity
);
7818 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7822 LeaveCriticalSection( &freetype_cs
);
7826 /*************************************************************
7827 * freetype_GetFontData
7829 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7831 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7835 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7836 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7839 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7840 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7841 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7843 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7846 /*************************************************************
7847 * freetype_GetTextFace
7849 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7852 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7856 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7857 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7860 n
= strlenW(physdev
->font
->name
) + 1;
7863 lstrcpynW(str
, physdev
->font
->name
, count
);
7869 /*************************************************************
7870 * freetype_GetTextCharsetInfo
7872 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7874 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7878 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7879 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7881 if (fs
) *fs
= physdev
->font
->fs
;
7882 return physdev
->font
->charset
;
7885 /* Retrieve a list of supported Unicode ranges for a given font.
7886 * Can be called with NULL gs to calculate the buffer size. Returns
7887 * the number of ranges found.
7889 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7891 DWORD num_ranges
= 0;
7893 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7896 FT_ULong char_code
, char_code_prev
;
7899 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7901 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7902 face
->num_glyphs
, glyph_code
, char_code
);
7904 if (!glyph_code
) return 0;
7908 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7909 gs
->ranges
[0].cGlyphs
= 0;
7910 gs
->cGlyphsSupported
= 0;
7916 if (char_code
< char_code_prev
)
7918 ERR("expected increasing char code from FT_Get_Next_Char\n");
7921 if (char_code
- char_code_prev
> 1)
7926 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7927 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7928 gs
->cGlyphsSupported
++;
7933 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7934 gs
->cGlyphsSupported
++;
7936 char_code_prev
= char_code
;
7937 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7941 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7946 /*************************************************************
7947 * freetype_GetFontUnicodeRanges
7949 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7951 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7952 DWORD size
, num_ranges
;
7956 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7957 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7960 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7961 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7964 glyphset
->cbThis
= size
;
7965 glyphset
->cRanges
= num_ranges
;
7966 glyphset
->flAccel
= 0;
7971 /*************************************************************
7972 * freetype_FontIsLinked
7974 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7976 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7981 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7982 return dev
->funcs
->pFontIsLinked( dev
);
7986 EnterCriticalSection( &freetype_cs
);
7987 ret
= !list_empty(&physdev
->font
->child_fonts
);
7988 LeaveCriticalSection( &freetype_cs
);
7992 /*************************************************************************
7993 * GetRasterizerCaps (GDI32.@)
7995 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7997 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7998 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7999 lprs
->nLanguageID
= 0;
8003 /*************************************************************
8004 * freetype_GdiRealizationInfo
8006 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
8008 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8009 realization_info_t
*info
= ptr
;
8013 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
8014 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
8017 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
8020 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8023 info
->cache_num
= physdev
->font
->cache_num
;
8024 info
->unknown2
= -1;
8028 /*************************************************************************
8029 * Kerning support for TrueType fonts
8031 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8033 struct TT_kern_table
8039 struct TT_kern_subtable
8048 USHORT horizontal
: 1;
8050 USHORT cross_stream
: 1;
8051 USHORT override
: 1;
8052 USHORT reserved1
: 4;
8058 struct TT_format0_kern_subtable
8062 USHORT entrySelector
;
8073 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8074 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8075 const USHORT
*glyph_to_char
,
8076 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8079 const struct TT_kern_pair
*tt_kern_pair
;
8081 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8083 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8085 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8086 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8087 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8089 if (!kern_pair
|| !cPairs
)
8092 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8094 nPairs
= min(nPairs
, cPairs
);
8096 for (i
= 0; i
< nPairs
; i
++)
8098 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8099 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8100 /* this algorithm appears to better match what Windows does */
8101 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8102 if (kern_pair
->iKernAmount
< 0)
8104 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8105 kern_pair
->iKernAmount
-= font
->ppem
;
8107 else if (kern_pair
->iKernAmount
> 0)
8109 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8110 kern_pair
->iKernAmount
+= font
->ppem
;
8112 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8114 TRACE("left %u right %u value %d\n",
8115 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8119 TRACE("copied %u entries\n", nPairs
);
8123 /*************************************************************
8124 * freetype_GetKerningPairs
8126 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8130 const struct TT_kern_table
*tt_kern_table
;
8131 const struct TT_kern_subtable
*tt_kern_subtable
;
8133 USHORT
*glyph_to_char
;
8135 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8137 if (!(font
= physdev
->font
))
8139 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8140 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8144 EnterCriticalSection( &freetype_cs
);
8145 if (font
->total_kern_pairs
!= (DWORD
)-1)
8147 if (cPairs
&& kern_pair
)
8149 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8150 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8152 else cPairs
= font
->total_kern_pairs
;
8154 LeaveCriticalSection( &freetype_cs
);
8158 font
->total_kern_pairs
= 0;
8160 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8162 if (length
== GDI_ERROR
)
8164 TRACE("no kerning data in the font\n");
8165 LeaveCriticalSection( &freetype_cs
);
8169 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8172 WARN("Out of memory\n");
8173 LeaveCriticalSection( &freetype_cs
);
8177 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8179 /* build a glyph index to char code map */
8180 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8183 WARN("Out of memory allocating a glyph index to char code map\n");
8184 HeapFree(GetProcessHeap(), 0, buf
);
8185 LeaveCriticalSection( &freetype_cs
);
8189 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8195 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8197 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8198 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8202 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8204 /* FIXME: This doesn't match what Windows does: it does some fancy
8205 * things with duplicate glyph index to char code mappings, while
8206 * we just avoid overriding existing entries.
8208 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8209 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8211 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8218 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8219 for (n
= 0; n
<= 65535; n
++)
8220 glyph_to_char
[n
] = (USHORT
)n
;
8223 tt_kern_table
= buf
;
8224 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8225 TRACE("version %u, nTables %u\n",
8226 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8228 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8230 for (i
= 0; i
< nTables
; i
++)
8232 struct TT_kern_subtable tt_kern_subtable_copy
;
8234 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8235 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8236 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8238 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8239 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8240 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8242 /* According to the TrueType specification this is the only format
8243 * that will be properly interpreted by Windows and OS/2
8245 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8247 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8249 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8250 glyph_to_char
, NULL
, 0);
8251 font
->total_kern_pairs
+= new_chunk
;
8253 if (!font
->kern_pairs
)
8254 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8255 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8257 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8258 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8260 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8261 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8264 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8266 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8269 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8270 HeapFree(GetProcessHeap(), 0, buf
);
8272 if (cPairs
&& kern_pair
)
8274 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8275 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8277 else cPairs
= font
->total_kern_pairs
;
8279 LeaveCriticalSection( &freetype_cs
);
8283 static const struct gdi_dc_funcs freetype_funcs
=
8285 NULL
, /* pAbortDoc */
8286 NULL
, /* pAbortPath */
8287 NULL
, /* pAlphaBlend */
8288 NULL
, /* pAngleArc */
8291 NULL
, /* pBeginPath */
8292 NULL
, /* pBlendImage */
8294 NULL
, /* pCloseFigure */
8295 NULL
, /* pCreateCompatibleDC */
8296 freetype_CreateDC
, /* pCreateDC */
8297 freetype_DeleteDC
, /* pDeleteDC */
8298 NULL
, /* pDeleteObject */
8299 NULL
, /* pDeviceCapabilities */
8300 NULL
, /* pEllipse */
8302 NULL
, /* pEndPage */
8303 NULL
, /* pEndPath */
8304 freetype_EnumFonts
, /* pEnumFonts */
8305 NULL
, /* pEnumICMProfiles */
8306 NULL
, /* pExcludeClipRect */
8307 NULL
, /* pExtDeviceMode */
8308 NULL
, /* pExtEscape */
8309 NULL
, /* pExtFloodFill */
8310 NULL
, /* pExtSelectClipRgn */
8311 NULL
, /* pExtTextOut */
8312 NULL
, /* pFillPath */
8313 NULL
, /* pFillRgn */
8314 NULL
, /* pFlattenPath */
8315 freetype_FontIsLinked
, /* pFontIsLinked */
8316 NULL
, /* pFrameRgn */
8317 NULL
, /* pGdiComment */
8318 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
8319 NULL
, /* pGetBoundsRect */
8320 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8321 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8322 freetype_GetCharWidth
, /* pGetCharWidth */
8323 NULL
, /* pGetDeviceCaps */
8324 NULL
, /* pGetDeviceGammaRamp */
8325 freetype_GetFontData
, /* pGetFontData */
8326 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8327 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8328 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8329 NULL
, /* pGetICMProfile */
8330 NULL
, /* pGetImage */
8331 freetype_GetKerningPairs
, /* pGetKerningPairs */
8332 NULL
, /* pGetNearestColor */
8333 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8334 NULL
, /* pGetPixel */
8335 NULL
, /* pGetSystemPaletteEntries */
8336 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8337 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8338 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8339 freetype_GetTextFace
, /* pGetTextFace */
8340 freetype_GetTextMetrics
, /* pGetTextMetrics */
8341 NULL
, /* pGradientFill */
8342 NULL
, /* pIntersectClipRect */
8343 NULL
, /* pInvertRgn */
8345 NULL
, /* pModifyWorldTransform */
8347 NULL
, /* pOffsetClipRgn */
8348 NULL
, /* pOffsetViewportOrg */
8349 NULL
, /* pOffsetWindowOrg */
8350 NULL
, /* pPaintRgn */
8353 NULL
, /* pPolyBezier */
8354 NULL
, /* pPolyBezierTo */
8355 NULL
, /* pPolyDraw */
8356 NULL
, /* pPolyPolygon */
8357 NULL
, /* pPolyPolyline */
8358 NULL
, /* pPolygon */
8359 NULL
, /* pPolyline */
8360 NULL
, /* pPolylineTo */
8361 NULL
, /* pPutImage */
8362 NULL
, /* pRealizeDefaultPalette */
8363 NULL
, /* pRealizePalette */
8364 NULL
, /* pRectangle */
8365 NULL
, /* pResetDC */
8366 NULL
, /* pRestoreDC */
8367 NULL
, /* pRoundRect */
8369 NULL
, /* pScaleViewportExt */
8370 NULL
, /* pScaleWindowExt */
8371 NULL
, /* pSelectBitmap */
8372 NULL
, /* pSelectBrush */
8373 NULL
, /* pSelectClipPath */
8374 freetype_SelectFont
, /* pSelectFont */
8375 NULL
, /* pSelectPalette */
8376 NULL
, /* pSelectPen */
8377 NULL
, /* pSetArcDirection */
8378 NULL
, /* pSetBkColor */
8379 NULL
, /* pSetBkMode */
8380 NULL
, /* pSetDCBrushColor */
8381 NULL
, /* pSetDCPenColor */
8382 NULL
, /* pSetDIBColorTable */
8383 NULL
, /* pSetDIBitsToDevice */
8384 NULL
, /* pSetDeviceClipping */
8385 NULL
, /* pSetDeviceGammaRamp */
8386 NULL
, /* pSetLayout */
8387 NULL
, /* pSetMapMode */
8388 NULL
, /* pSetMapperFlags */
8389 NULL
, /* pSetPixel */
8390 NULL
, /* pSetPolyFillMode */
8391 NULL
, /* pSetROP2 */
8392 NULL
, /* pSetRelAbs */
8393 NULL
, /* pSetStretchBltMode */
8394 NULL
, /* pSetTextAlign */
8395 NULL
, /* pSetTextCharacterExtra */
8396 NULL
, /* pSetTextColor */
8397 NULL
, /* pSetTextJustification */
8398 NULL
, /* pSetViewportExt */
8399 NULL
, /* pSetViewportOrg */
8400 NULL
, /* pSetWindowExt */
8401 NULL
, /* pSetWindowOrg */
8402 NULL
, /* pSetWorldTransform */
8403 NULL
, /* pStartDoc */
8404 NULL
, /* pStartPage */
8405 NULL
, /* pStretchBlt */
8406 NULL
, /* pStretchDIBits */
8407 NULL
, /* pStrokeAndFillPath */
8408 NULL
, /* pStrokePath */
8409 NULL
, /* pUnrealizePalette */
8410 NULL
, /* pWidenPath */
8411 NULL
, /* wine_get_wgl_driver */
8412 GDI_PRIORITY_FONT_DRV
/* priority */
8415 #else /* HAVE_FREETYPE */
8417 /*************************************************************************/
8419 BOOL
WineEngInit(void)
8424 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8426 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8430 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8432 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8436 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8438 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8442 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8443 LPCWSTR font_file
, LPCWSTR font_path
)
8449 /*************************************************************************
8450 * GetRasterizerCaps (GDI32.@)
8452 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8454 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8456 lprs
->nLanguageID
= 0;
8460 #endif /* HAVE_FREETYPE */