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 */
80 #ifdef HAVE_FT2BUILD_H
82 #include FT_FREETYPE_H
85 #include FT_TRUETYPE_TABLES_H
86 #include FT_SFNT_NAMES_H
87 #include FT_TRUETYPE_IDS_H
89 #include FT_TRIGONOMETRY_H
91 #include FT_WINFONTS_H
92 #ifdef FT_LCD_FILTER_H
93 #include FT_LCD_FILTER_H
95 #endif /* HAVE_FT2BUILD_H */
100 #include "winerror.h"
103 #include "gdi_private.h"
104 #include "wine/library.h"
105 #include "wine/unicode.h"
106 #include "wine/debug.h"
107 #include "wine/list.h"
109 #include "resource.h"
111 WINE_DEFAULT_DEBUG_CHANNEL(font
);
115 #ifndef HAVE_FT_TRUETYPEENGINETYPE
118 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
119 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
120 FT_TRUETYPE_ENGINE_TYPE_PATENTED
121 } FT_TrueTypeEngineType
;
124 static FT_Library library
= 0;
131 static FT_Version_t FT_Version
;
132 static DWORD FT_SimpleVersion
;
134 static void *ft_handle
= NULL
;
136 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
137 MAKE_FUNCPTR(FT_Done_Face
);
138 MAKE_FUNCPTR(FT_Get_Char_Index
);
139 MAKE_FUNCPTR(FT_Get_First_Char
);
140 MAKE_FUNCPTR(FT_Get_Next_Char
);
141 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
142 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
143 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
144 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
145 MAKE_FUNCPTR(FT_Init_FreeType
);
146 MAKE_FUNCPTR(FT_Library_Version
);
147 MAKE_FUNCPTR(FT_Load_Glyph
);
148 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
149 MAKE_FUNCPTR(FT_Matrix_Multiply
);
150 #ifdef FT_MULFIX_INLINED
151 #define pFT_MulFix FT_MULFIX_INLINED
153 MAKE_FUNCPTR(FT_MulFix
);
155 MAKE_FUNCPTR(FT_New_Face
);
156 MAKE_FUNCPTR(FT_New_Memory_Face
);
157 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
158 MAKE_FUNCPTR(FT_Outline_Get_CBox
);
159 MAKE_FUNCPTR(FT_Outline_Transform
);
160 MAKE_FUNCPTR(FT_Outline_Translate
);
161 MAKE_FUNCPTR(FT_Render_Glyph
);
162 MAKE_FUNCPTR(FT_Select_Charmap
);
163 MAKE_FUNCPTR(FT_Set_Charmap
);
164 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
165 MAKE_FUNCPTR(FT_Vector_Transform
);
166 MAKE_FUNCPTR(FT_Vector_Unit
);
167 static FT_Error (*pFT_Outline_Embolden
)(FT_Outline
*, FT_Pos
);
168 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
169 #ifdef FT_LCD_FILTER_H
170 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute
);
176 MAKE_FUNCPTR(FcFontList
);
177 MAKE_FUNCPTR(FcFontSetDestroy
);
178 MAKE_FUNCPTR(FcInit
);
179 MAKE_FUNCPTR(FcObjectSetAdd
);
180 MAKE_FUNCPTR(FcObjectSetCreate
);
181 MAKE_FUNCPTR(FcObjectSetDestroy
);
182 MAKE_FUNCPTR(FcPatternCreate
);
183 MAKE_FUNCPTR(FcPatternDestroy
);
184 MAKE_FUNCPTR(FcPatternGetBool
);
185 MAKE_FUNCPTR(FcPatternGetInteger
);
186 MAKE_FUNCPTR(FcPatternGetString
);
192 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
193 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
194 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
197 #ifndef ft_encoding_none
198 #define FT_ENCODING_NONE ft_encoding_none
200 #ifndef ft_encoding_ms_symbol
201 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
203 #ifndef ft_encoding_unicode
204 #define FT_ENCODING_UNICODE ft_encoding_unicode
206 #ifndef ft_encoding_apple_roman
207 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
210 #ifdef WORDS_BIGENDIAN
211 #define GET_BE_WORD(x) (x)
213 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
216 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
223 FT_Short internal_leading
;
226 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
227 So to let this compile on older versions of FreeType we'll define the
228 new structure here. */
230 FT_Short height
, width
;
231 FT_Pos size
, x_ppem
, y_ppem
;
237 NEWTEXTMETRICEXW ntm
;
241 typedef struct tagFace
{
243 unsigned int refcount
;
250 DWORD font_data_size
;
254 FT_Fixed font_version
;
256 Bitmap_Size size
; /* set if face is a bitmap */
257 DWORD flags
; /* ADDFONT flags */
258 struct tagFamily
*family
;
259 /* Cached data for Enum */
260 struct enum_data
*cached_enum_data
;
263 #define ADDFONT_EXTERNAL_FONT 0x01
264 #define ADDFONT_ALLOW_BITMAP 0x02
265 #define ADDFONT_ADD_TO_CACHE 0x04
266 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
267 #define ADDFONT_VERTICAL_FONT 0x10
268 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
270 typedef struct tagFamily
{
272 unsigned int refcount
;
276 struct list
*replacement
;
281 ABC abc
; /* metrics of the unrotated char */
297 typedef struct tagGdiFont GdiFont
;
307 struct list unused_entry
;
308 unsigned int refcount
;
311 OUTLINETEXTMETRICW
*potm
;
312 DWORD total_kern_pairs
;
313 KERNINGPAIR
*kern_pairs
;
314 struct list child_fonts
;
316 /* the following members can be accessed without locking, they are never modified after creation */
318 struct font_mapping
*mapping
;
334 UINT ntmCellHeight
, ntmAvgWidth
;
338 const VOID
*vert_feature
;
344 const WCHAR
*font_name
;
349 struct enum_charset_element
{
352 WCHAR name
[LF_FACESIZE
];
355 struct enum_charset_list
{
357 struct enum_charset_element element
[32];
360 #define GM_BLOCK_SIZE 128
361 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
363 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
364 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
365 static unsigned int unused_font_count
;
366 #define UNUSED_CACHE_SIZE 10
367 static struct list system_links
= LIST_INIT(system_links
);
369 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
371 static struct list font_list
= LIST_INIT(font_list
);
373 struct freetype_physdev
375 struct gdi_physdev dev
;
379 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
381 return (struct freetype_physdev
*)dev
;
384 static const struct gdi_dc_funcs freetype_funcs
;
386 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
387 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
388 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
390 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
391 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
392 'W','i','n','d','o','w','s','\\',
393 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
394 'F','o','n','t','s','\0'};
396 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
397 'W','i','n','d','o','w','s',' ','N','T','\\',
398 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
399 'F','o','n','t','s','\0'};
401 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
402 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
403 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
404 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
406 static const WCHAR
* const SystemFontValues
[] = {
413 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
414 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
416 /* Interesting and well-known (frequently-assumed!) font names */
417 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
418 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 };
419 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
420 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
421 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
422 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
423 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
424 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
426 static const WCHAR arial
[] = {'A','r','i','a','l',0};
427 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
428 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};
429 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};
430 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
431 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
432 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
433 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
434 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
435 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
437 static const WCHAR
*default_serif_list
[] =
441 bitstream_vera_serif
,
445 static const WCHAR
*default_fixed_list
[] =
449 bitstream_vera_sans_mono
,
453 static const WCHAR
*default_sans_list
[] =
466 typedef struct tagFontSubst
{
472 /* Registry font cache key and value names */
473 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
474 'F','o','n','t','s',0};
475 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
476 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
477 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
478 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
479 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
480 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
481 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
482 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
483 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
484 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
485 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
486 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
487 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
488 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
489 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
502 static struct list mappings_list
= LIST_INIT( mappings_list
);
504 static UINT default_aa_flags
;
505 static HKEY hkey_font_cache
;
507 static CRITICAL_SECTION freetype_cs
;
508 static CRITICAL_SECTION_DEBUG critsect_debug
=
511 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
512 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
514 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
516 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
518 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
519 static BOOL use_default_fallback
= FALSE
;
521 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
*vert
);
522 static BOOL
get_outline_text_metrics(GdiFont
*font
);
523 static BOOL
get_bitmap_text_metrics(GdiFont
*font
);
524 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
525 static void remove_face_from_cache( Face
*face
);
527 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
528 'W','i','n','d','o','w','s',' ','N','T','\\',
529 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
530 'S','y','s','t','e','m','L','i','n','k',0};
532 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
533 'F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 /****************************************
537 * Notes on .fon files
539 * The fonts System, FixedSys and Terminal are special. There are typically multiple
540 * versions installed for different resolutions and codepages. Windows stores which one to use
541 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
543 * FIXEDFON.FON FixedSys
545 * OEMFONT.FON Terminal
546 * LogPixels Current dpi set by the display control panel applet
547 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
548 * also has a LogPixels value that appears to mirror this)
550 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
551 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
552 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
553 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
554 * so that makes sense.
556 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
557 * to be mapped into the registry on Windows 2000 at least).
560 * ega80woa.fon=ega80850.fon
561 * ega40woa.fon=ega40850.fon
562 * cga80woa.fon=cga80850.fon
563 * cga40woa.fon=cga40850.fon
566 /* These are all structures needed for the GSUB table */
568 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
584 GSUB_ScriptRecord ScriptRecord
[1];
590 } GSUB_LangSysRecord
;
595 GSUB_LangSysRecord LangSysRecord
[1];
599 WORD LookupOrder
; /* Reserved */
600 WORD ReqFeatureIndex
;
602 WORD FeatureIndex
[1];
608 } GSUB_FeatureRecord
;
612 GSUB_FeatureRecord FeatureRecord
[1];
616 WORD FeatureParams
; /* Reserved */
618 WORD LookupListIndex
[1];
637 } GSUB_CoverageFormat1
;
642 WORD StartCoverageIndex
;
648 GSUB_RangeRecord RangeRecord
[1];
649 } GSUB_CoverageFormat2
;
652 WORD SubstFormat
; /* = 1 */
655 } GSUB_SingleSubstFormat1
;
658 WORD SubstFormat
; /* = 2 */
662 }GSUB_SingleSubstFormat2
;
664 #ifdef HAVE_CARBON_CARBON_H
665 static char *find_cache_dir(void)
669 static char cached_path
[MAX_PATH
];
670 static const char *wine
= "/Wine", *fonts
= "/Fonts";
672 if(*cached_path
) return cached_path
;
674 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
677 WARN("can't create cached data folder\n");
680 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
683 WARN("can't create cached data path\n");
687 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
689 ERR("Could not create full path\n");
693 strcat(cached_path
, wine
);
695 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
697 WARN("Couldn't mkdir %s\n", cached_path
);
701 strcat(cached_path
, fonts
);
702 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
704 WARN("Couldn't mkdir %s\n", cached_path
);
711 /******************************************************************
714 * Extracts individual TrueType font files from a Mac suitcase font
715 * and saves them into the user's caches directory (see
717 * Returns a NULL terminated array of filenames.
719 * We do this because they are apps that try to read ttf files
720 * themselves and they don't like Mac suitcase files.
722 static char **expand_mac_font(const char *path
)
729 const char *filename
;
733 unsigned int size
, max_size
;
736 TRACE("path %s\n", path
);
738 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
741 WARN("failed to get ref\n");
745 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
748 TRACE("no data fork, so trying resource fork\n");
749 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
752 TRACE("unable to open resource fork\n");
759 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
762 CloseResFile(res_ref
);
766 out_dir
= find_cache_dir();
768 filename
= strrchr(path
, '/');
769 if(!filename
) filename
= path
;
772 /* output filename has the form out_dir/filename_%04x.ttf */
773 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
780 unsigned short *num_faces_ptr
, num_faces
, face
;
783 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
785 fond
= Get1IndResource(fond_res
, idx
);
787 TRACE("got fond resource %d\n", idx
);
790 fam_rec
= *(FamRec
**)fond
;
791 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
792 num_faces
= GET_BE_WORD(*num_faces_ptr
);
794 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
795 TRACE("num faces %04x\n", num_faces
);
796 for(face
= 0; face
< num_faces
; face
++, assoc
++)
799 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
800 unsigned short size
, font_id
;
803 size
= GET_BE_WORD(assoc
->fontSize
);
804 font_id
= GET_BE_WORD(assoc
->fontID
);
807 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
811 TRACE("trying to load sfnt id %04x\n", font_id
);
812 sfnt
= GetResource(sfnt_res
, font_id
);
815 TRACE("can't get sfnt resource %04x\n", font_id
);
819 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
824 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
826 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
827 if(fd
!= -1 || errno
== EEXIST
)
831 unsigned char *sfnt_data
;
834 sfnt_data
= *(unsigned char**)sfnt
;
835 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
839 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
842 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
844 ret
.array
[ret
.size
++] = output
;
848 WARN("unable to create %s\n", output
);
849 HeapFree(GetProcessHeap(), 0, output
);
852 ReleaseResource(sfnt
);
855 ReleaseResource(fond
);
858 CloseResFile(res_ref
);
863 #endif /* HAVE_CARBON_CARBON_H */
865 static inline BOOL
is_win9x(void)
867 return GetVersion() & 0x80000000;
870 This function builds an FT_Fixed from a double. It fails if the absolute
871 value of the float number is greater than 32768.
873 static inline FT_Fixed
FT_FixedFromFloat(double f
)
879 This function builds an FT_Fixed from a FIXED. It simply put f.value
880 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
882 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
884 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
887 static BOOL
is_hinting_enabled(void)
889 static int enabled
= -1;
893 /* Use the >= 2.2.0 function if available */
894 if (pFT_Get_TrueType_Engine_Type
)
896 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
897 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
899 else enabled
= FALSE
;
900 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
905 static BOOL
is_subpixel_rendering_enabled( void )
907 #ifdef FT_LCD_FILTER_H
908 static int enabled
= -1;
911 enabled
= (pFT_Library_SetLcdFilter
&&
912 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
913 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
922 static const struct list
*get_face_list_from_family(const Family
*family
)
924 if (!list_empty(&family
->faces
))
925 return &family
->faces
;
927 return family
->replacement
;
930 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
936 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
938 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
940 const struct list
*face_list
;
941 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
943 face_list
= get_face_list_from_family(family
);
944 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
948 file
= strrchrW(face
->file
, '/');
953 if(strcmpiW(file
, file_name
)) continue;
961 static Family
*find_family_from_name(const WCHAR
*name
)
965 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
967 if(!strcmpiW(family
->FamilyName
, name
))
974 static Family
*find_family_from_any_name(const WCHAR
*name
)
978 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
980 if(!strcmpiW(family
->FamilyName
, name
))
982 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
989 static void DumpSubstList(void)
993 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
995 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
996 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
997 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
999 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1000 debugstr_w(psub
->to
.name
));
1005 static LPWSTR
strdupW(LPCWSTR p
)
1008 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1009 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1010 memcpy(ret
, p
, len
);
1014 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1019 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1021 if(!strcmpiW(element
->from
.name
, from_name
) &&
1022 (element
->from
.charset
== from_charset
||
1023 element
->from
.charset
== -1))
1030 #define ADD_FONT_SUBST_FORCE 1
1032 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1034 FontSubst
*from_exist
, *to_exist
;
1036 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1038 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1040 list_remove(&from_exist
->entry
);
1041 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1042 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1043 HeapFree(GetProcessHeap(), 0, from_exist
);
1049 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1053 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1054 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1057 list_add_tail(subst_list
, &subst
->entry
);
1062 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1063 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1064 HeapFree(GetProcessHeap(), 0, subst
);
1068 static WCHAR
*towstr(UINT cp
, const char *str
)
1073 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1074 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1075 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1079 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1081 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1082 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1083 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1087 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1089 CHAR
*p
= strrchr(str
, ',');
1093 nc
->charset
= strtol(p
+1, NULL
, 10);
1096 nc
->name
= towstr(CP_ACP
, str
);
1099 static void LoadSubstList(void)
1103 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1107 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1108 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1109 &hkey
) == ERROR_SUCCESS
) {
1111 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1112 &valuelen
, &datalen
, NULL
, NULL
);
1114 valuelen
++; /* returned value doesn't include room for '\0' */
1115 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1116 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1120 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1121 &dlen
) == ERROR_SUCCESS
) {
1122 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1124 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1125 split_subst_info(&psub
->from
, value
);
1126 split_subst_info(&psub
->to
, data
);
1128 /* Win 2000 doesn't allow mapping between different charsets
1129 or mapping of DEFAULT_CHARSET */
1130 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1131 psub
->to
.charset
== DEFAULT_CHARSET
) {
1132 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1133 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1134 HeapFree(GetProcessHeap(), 0, psub
);
1136 add_font_subst(&font_subst_list
, psub
, 0);
1138 /* reset dlen and vlen */
1142 HeapFree(GetProcessHeap(), 0, data
);
1143 HeapFree(GetProcessHeap(), 0, value
);
1149 static const LANGID mac_langid_table
[] =
1151 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
1152 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
1153 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
1154 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
1155 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
1156 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
1157 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
1158 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
1159 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
1160 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
1161 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
1162 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
1163 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
1164 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
1165 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
1166 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
1167 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
1168 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
1169 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
1170 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1171 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
1172 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
1173 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
1174 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
1175 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
1176 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
1177 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
1178 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
1179 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
1180 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
1181 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
1182 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
1183 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
1184 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1185 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
1186 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
1187 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
1188 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
1189 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
1190 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
1191 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
1192 0, /* TT_MAC_LANGID_YIDDISH */
1193 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
1194 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
1195 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
1196 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
1197 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
1198 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
1199 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
1200 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
1201 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1202 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
1203 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
1204 0, /* TT_MAC_LANGID_MOLDAVIAN */
1205 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
1206 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
1207 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
1208 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
1209 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1210 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
1211 0, /* TT_MAC_LANGID_KURDISH */
1212 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
1213 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
1214 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
1215 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
1216 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
1217 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
1218 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
1219 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
1220 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
1221 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
1222 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
1223 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
1224 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
1225 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
1226 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
1227 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
1228 0, /* TT_MAC_LANGID_BURMESE */
1229 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
1230 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
1231 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
1232 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
1233 0, /* TT_MAC_LANGID_TAGALOG */
1234 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1235 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1236 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
1237 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
1238 0, /* TT_MAC_LANGID_GALLA */
1239 0, /* TT_MAC_LANGID_SOMALI */
1240 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
1241 0, /* TT_MAC_LANGID_RUANDA */
1242 0, /* TT_MAC_LANGID_RUNDI */
1243 0, /* TT_MAC_LANGID_CHEWA */
1244 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
1245 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
1246 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1248 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
1249 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
1250 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
1251 0, /* TT_MAC_LANGID_LATIN */
1252 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
1253 0, /* TT_MAC_LANGID_GUARANI */
1254 0, /* TT_MAC_LANGID_AYMARA */
1255 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
1256 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
1257 0, /* TT_MAC_LANGID_DZONGKHA */
1258 0, /* TT_MAC_LANGID_JAVANESE */
1259 0, /* TT_MAC_LANGID_SUNDANESE */
1260 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
1261 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
1262 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
1263 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
1264 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1265 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
1266 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
1267 0, /* TT_MAC_LANGID_TONGAN */
1268 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1269 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
1270 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1273 static inline WORD
get_mac_code_page( const FT_SfntName
*name
)
1275 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
1276 return 10000 + name
->encoding_id
;
1279 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
1284 switch (name
->platform_id
)
1286 case TT_PLATFORM_MICROSOFT
:
1287 res
+= 5; /* prefer the Microsoft name */
1288 switch (name
->encoding_id
)
1290 case TT_MS_ID_UNICODE_CS
:
1291 case TT_MS_ID_SYMBOL_CS
:
1292 name_lang
= name
->language_id
;
1298 case TT_PLATFORM_MACINTOSH
:
1299 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
1300 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1301 name_lang
= mac_langid_table
[name
->language_id
];
1303 case TT_PLATFORM_APPLE_UNICODE
:
1304 res
+= 2; /* prefer Unicode encodings */
1305 switch (name
->encoding_id
)
1307 case TT_APPLE_ID_DEFAULT
:
1308 case TT_APPLE_ID_ISO_10646
:
1309 case TT_APPLE_ID_UNICODE_2_0
:
1310 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1311 name_lang
= mac_langid_table
[name
->language_id
];
1320 if (name_lang
== lang
) res
+= 30;
1321 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
1322 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
1326 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
1332 switch (name
->platform_id
)
1334 case TT_PLATFORM_APPLE_UNICODE
:
1335 case TT_PLATFORM_MICROSOFT
:
1336 ret
= HeapAlloc( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
1337 for (i
= 0; i
< name
->string_len
/ 2; i
++)
1338 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
1341 case TT_PLATFORM_MACINTOSH
:
1342 codepage
= get_mac_code_page( name
);
1343 i
= MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, NULL
, 0 );
1344 ret
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(WCHAR
) );
1345 MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, ret
, i
);
1352 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
1355 FT_UInt num_names
, name_index
;
1356 int res
, best_lang
= 0, best_index
= -1;
1358 if (!FT_IS_SFNT(ft_face
)) return NULL
;
1360 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
1362 for (name_index
= 0; name_index
< num_names
; name_index
++)
1364 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
1365 if (name
.name_id
!= name_id
) continue;
1366 res
= match_name_table_language( &name
, language_id
);
1367 if (res
> best_lang
)
1370 best_index
= name_index
;
1374 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
1376 WCHAR
*ret
= copy_name_table_string( &name
);
1377 TRACE( "name %u found platform %u lang %04x %s\n",
1378 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
1384 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1386 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1387 if (f1
->scalable
) return TRUE
;
1388 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1389 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1392 static void release_family( Family
*family
)
1394 if (--family
->refcount
) return;
1395 assert( list_empty( &family
->faces
));
1396 list_remove( &family
->entry
);
1397 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1398 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1399 HeapFree( GetProcessHeap(), 0, family
);
1402 static void release_face( Face
*face
)
1404 if (--face
->refcount
) return;
1407 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1408 list_remove( &face
->entry
);
1409 release_family( face
->family
);
1411 HeapFree( GetProcessHeap(), 0, face
->file
);
1412 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1413 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1414 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1415 HeapFree( GetProcessHeap(), 0, face
);
1418 static inline int style_order(const Face
*face
)
1420 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1428 case NTM_BOLD
| NTM_ITALIC
:
1431 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1432 debugstr_w(face
->family
->FamilyName
),
1433 debugstr_w(face
->StyleName
),
1439 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1443 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1445 if (faces_equal( face
, cursor
))
1447 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1448 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1449 cursor
->font_version
, face
->font_version
);
1451 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1454 TRACE("Font %s already in list, refcount now %d\n",
1455 debugstr_w(face
->file
), cursor
->refcount
);
1458 if (face
->font_version
<= cursor
->font_version
)
1460 TRACE("Original font %s is newer so skipping %s\n",
1461 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1466 TRACE("Replacing original %s with %s\n",
1467 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1468 list_add_before( &cursor
->entry
, &face
->entry
);
1469 face
->family
= family
;
1472 release_face( cursor
);
1477 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1479 if (style_order( face
) < style_order( cursor
)) break;
1482 list_add_before( &cursor
->entry
, &face
->entry
);
1483 face
->family
= family
;
1489 /****************************************************************
1490 * NB This function stores the ptrs to the strings to save copying.
1491 * Don't free them after calling.
1493 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1495 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1496 family
->refcount
= 1;
1497 family
->FamilyName
= name
;
1498 family
->EnglishName
= english_name
;
1499 list_init( &family
->faces
);
1500 family
->replacement
= &family
->faces
;
1501 list_add_tail( &font_list
, &family
->entry
);
1506 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1508 DWORD type
, size
= sizeof(DWORD
);
1510 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1511 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1514 return ERROR_BAD_CONFIGURATION
;
1516 return ERROR_SUCCESS
;
1519 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1521 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1524 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1526 DWORD needed
, strike_index
= 0;
1529 /* If we have a File Name key then this is a real font, not just the parent
1530 key of a bunch of non-scalable strikes */
1531 needed
= buffer_size
;
1532 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1535 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1536 face
->cached_enum_data
= NULL
;
1537 face
->family
= NULL
;
1540 face
->file
= strdupW( buffer
);
1541 face
->StyleName
= strdupW(face_name
);
1543 needed
= buffer_size
;
1544 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1545 face
->FullName
= strdupW( buffer
);
1547 face
->FullName
= NULL
;
1549 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1550 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1551 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1552 reg_load_dword(hkey_face
, face_flags_value
, (DWORD
*)&face
->flags
);
1554 needed
= sizeof(face
->fs
);
1555 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1557 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1559 face
->scalable
= TRUE
;
1560 memset(&face
->size
, 0, sizeof(face
->size
));
1564 face
->scalable
= FALSE
;
1565 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1566 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1567 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1568 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1569 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1571 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1572 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1573 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1576 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1577 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1578 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1579 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1581 if (insert_face_in_family_list(face
, family
))
1582 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1584 release_face( face
);
1587 /* load bitmap strikes */
1589 needed
= buffer_size
;
1590 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1592 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1594 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1595 RegCloseKey(hkey_strike
);
1597 needed
= buffer_size
;
1601 /* move vertical fonts after their horizontal counterpart */
1602 /* assumes that font_list is already sorted by family name */
1603 static void reorder_vertical_fonts(void)
1605 Family
*family
, *next
, *vert_family
;
1606 struct list
*ptr
, *vptr
;
1607 struct list vertical_families
= LIST_INIT( vertical_families
);
1609 LIST_FOR_EACH_ENTRY_SAFE( family
, next
, &font_list
, Family
, entry
)
1611 if (family
->FamilyName
[0] != '@') continue;
1612 list_remove( &family
->entry
);
1613 list_add_tail( &vertical_families
, &family
->entry
);
1616 ptr
= list_head( &font_list
);
1617 vptr
= list_head( &vertical_families
);
1620 family
= LIST_ENTRY( ptr
, Family
, entry
);
1621 vert_family
= LIST_ENTRY( vptr
, Family
, entry
);
1622 if (strcmpiW( family
->FamilyName
, vert_family
->FamilyName
+ 1 ) > 0)
1624 list_remove( vptr
);
1625 list_add_before( ptr
, vptr
);
1626 vptr
= list_head( &vertical_families
);
1628 else ptr
= list_next( &font_list
, ptr
);
1630 list_move_tail( &font_list
, &vertical_families
);
1633 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1635 DWORD size
, family_index
= 0;
1640 size
= sizeof(buffer
);
1641 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1643 WCHAR
*english_family
= NULL
;
1644 WCHAR
*family_name
= strdupW( buffer
);
1645 DWORD face_index
= 0;
1647 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1648 TRACE("opened family key %s\n", debugstr_w(family_name
));
1649 size
= sizeof(buffer
);
1650 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1651 english_family
= strdupW( buffer
);
1653 family
= create_family(family_name
, english_family
);
1657 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1658 subst
->from
.name
= strdupW(english_family
);
1659 subst
->from
.charset
= -1;
1660 subst
->to
.name
= strdupW(family_name
);
1661 subst
->to
.charset
= -1;
1662 add_font_subst(&font_subst_list
, subst
, 0);
1665 size
= sizeof(buffer
);
1666 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1668 WCHAR
*face_name
= strdupW( buffer
);
1671 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1673 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1674 RegCloseKey(hkey_face
);
1676 HeapFree( GetProcessHeap(), 0, face_name
);
1677 size
= sizeof(buffer
);
1679 RegCloseKey(hkey_family
);
1680 release_family( family
);
1681 size
= sizeof(buffer
);
1684 reorder_vertical_fonts();
1687 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1690 HKEY hkey_wine_fonts
;
1692 /* We don't want to create the fonts key as volatile, so open this first */
1693 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1694 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1695 if(ret
!= ERROR_SUCCESS
)
1697 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1701 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1702 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1703 RegCloseKey(hkey_wine_fonts
);
1707 static void add_face_to_cache(Face
*face
)
1709 HKEY hkey_family
, hkey_face
;
1710 WCHAR
*face_key_name
;
1712 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1713 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1714 if(face
->family
->EnglishName
)
1715 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1716 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1719 face_key_name
= face
->StyleName
;
1722 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1723 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1724 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1726 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1729 HeapFree(GetProcessHeap(), 0, face_key_name
);
1731 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1732 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1734 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1735 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1737 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1738 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1739 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1740 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1742 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1746 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1747 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1748 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1749 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1750 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1751 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1753 RegCloseKey(hkey_face
);
1754 RegCloseKey(hkey_family
);
1757 static void remove_face_from_cache( Face
*face
)
1761 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1765 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1769 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1770 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1771 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1772 RegDeleteKeyW( hkey_family
, face_key_name
);
1773 HeapFree(GetProcessHeap(), 0, face_key_name
);
1775 RegCloseKey(hkey_family
);
1778 static WCHAR
*prepend_at(WCHAR
*family
)
1785 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1787 strcpyW(str
+ 1, family
);
1788 HeapFree(GetProcessHeap(), 0, family
);
1792 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1794 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
) );
1795 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1797 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1803 else if (!strcmpiW( *name
, *english
))
1805 HeapFree( GetProcessHeap(), 0, *english
);
1811 *name
= prepend_at( *name
);
1812 *english
= prepend_at( *english
);
1816 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1819 WCHAR
*name
, *english_name
;
1821 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1823 family
= find_family_from_name( name
);
1827 family
= create_family( name
, english_name
);
1830 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1831 subst
->from
.name
= strdupW( english_name
);
1832 subst
->from
.charset
= -1;
1833 subst
->to
.name
= strdupW( name
);
1834 subst
->to
.charset
= -1;
1835 add_font_subst( &font_subst_list
, subst
, 0 );
1840 HeapFree( GetProcessHeap(), 0, name
);
1841 HeapFree( GetProcessHeap(), 0, english_name
);
1848 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1850 FT_Fixed version
= 0;
1853 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1854 if (header
) version
= header
->Font_Revision
;
1859 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1862 FT_ULong table_size
= 0;
1864 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1865 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1866 if (flags
== 0) flags
= NTM_REGULAR
;
1868 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1869 flags
|= NTM_PS_OPENTYPE
;
1874 static inline void get_bitmap_size( FT_Face ft_face
, Bitmap_Size
*face_size
)
1876 My_FT_Bitmap_Size
*size
;
1877 FT_WinFNT_HeaderRec winfnt_header
;
1879 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1880 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1881 size
->height
, size
->width
, size
->size
>> 6,
1882 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1883 face_size
->height
= size
->height
;
1884 face_size
->width
= size
->width
;
1885 face_size
->size
= size
->size
;
1886 face_size
->x_ppem
= size
->x_ppem
;
1887 face_size
->y_ppem
= size
->y_ppem
;
1889 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
1890 face_size
->internal_leading
= winfnt_header
.internal_leading
;
1891 if (winfnt_header
.external_leading
> 0 &&
1892 (face_size
->height
==
1893 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
1894 face_size
->height
= winfnt_header
.pixel_height
;
1898 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1903 FT_WinFNT_HeaderRec winfnt_header
;
1906 memset( fs
, 0, sizeof(*fs
) );
1908 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1911 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1912 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1913 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1914 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1916 if (os2
->version
== 0)
1918 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1919 fs
->fsCsb
[0] = FS_LATIN1
;
1921 fs
->fsCsb
[0] = FS_SYMBOL
;
1925 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1926 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1931 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1933 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1934 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1935 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1940 if (fs
->fsCsb
[0] == 0)
1942 /* let's see if we can find any interesting cmaps */
1943 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1945 switch (ft_face
->charmaps
[i
]->encoding
)
1947 case FT_ENCODING_UNICODE
:
1948 case FT_ENCODING_APPLE_ROMAN
:
1949 fs
->fsCsb
[0] |= FS_LATIN1
;
1951 case FT_ENCODING_MS_SYMBOL
:
1952 fs
->fsCsb
[0] |= FS_SYMBOL
;
1961 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1965 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1968 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1969 if (!face
->StyleName
) face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1971 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1972 if (flags
& ADDFONT_VERTICAL_FONT
)
1973 face
->FullName
= prepend_at( face
->FullName
);
1979 face
->file
= towstr( CP_UNIXCP
, file
);
1980 face
->font_data_ptr
= NULL
;
1981 face
->font_data_size
= 0;
1982 if (!stat( file
, &st
))
1984 face
->dev
= st
.st_dev
;
1985 face
->ino
= st
.st_ino
;
1991 face
->font_data_ptr
= font_data_ptr
;
1992 face
->font_data_size
= font_data_size
;
1995 face
->face_index
= face_index
;
1996 get_fontsig( ft_face
, &face
->fs
);
1997 face
->ntmFlags
= get_ntm_flags( ft_face
);
1998 face
->font_version
= get_font_version( ft_face
);
2000 if (FT_IS_SCALABLE( ft_face
))
2002 memset( &face
->size
, 0, sizeof(face
->size
) );
2003 face
->scalable
= TRUE
;
2007 get_bitmap_size( ft_face
, &face
->size
);
2008 face
->scalable
= FALSE
;
2011 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
2012 face
->flags
= flags
;
2013 face
->family
= NULL
;
2014 face
->cached_enum_data
= NULL
;
2016 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2017 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
2018 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
2019 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
2024 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2025 FT_Long face_index
, DWORD flags
)
2030 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
2031 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
2032 if (insert_face_in_family_list( face
, family
))
2034 if (flags
& ADDFONT_ADD_TO_CACHE
)
2035 add_face_to_cache( face
);
2037 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
2038 debugstr_w(face
->StyleName
));
2040 release_face( face
);
2041 release_family( family
);
2044 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2045 FT_Long face_index
, BOOL allow_bitmap
)
2053 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
2054 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
2058 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
2059 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
2064 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
2068 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2069 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
2071 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2075 if (!FT_IS_SFNT( ft_face
))
2077 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
2079 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2085 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
2086 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
2087 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
2089 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2090 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
2094 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2095 we don't want to load these. */
2096 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
2100 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
2102 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
2108 if (!ft_face
->family_name
|| !ft_face
->style_name
)
2110 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
2116 pFT_Done_Face( ft_face
);
2120 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
2123 FT_Long face_index
= 0, num_faces
;
2126 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2127 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
2129 #ifdef HAVE_CARBON_CARBON_H
2132 char **mac_list
= expand_mac_font(file
);
2135 BOOL had_one
= FALSE
;
2137 for(cursor
= mac_list
; *cursor
; cursor
++)
2140 AddFontToList(*cursor
, NULL
, 0, flags
);
2141 HeapFree(GetProcessHeap(), 0, *cursor
);
2143 HeapFree(GetProcessHeap(), 0, mac_list
);
2148 #endif /* HAVE_CARBON_CARBON_H */
2151 const DWORD FS_DBCS_MASK
= FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
;
2154 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
2155 if (!ft_face
) return 0;
2157 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
2159 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
2160 pFT_Done_Face(ft_face
);
2164 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
2167 get_fontsig(ft_face
, &fs
);
2168 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
2170 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
2171 flags
| ADDFONT_VERTICAL_FONT
);
2175 num_faces
= ft_face
->num_faces
;
2176 pFT_Done_Face(ft_face
);
2177 } while(num_faces
> ++face_index
);
2181 static int remove_font_resource( const char *file
, DWORD flags
)
2183 Family
*family
, *family_next
;
2184 Face
*face
, *face_next
;
2188 if (stat( file
, &st
) == -1) return 0;
2189 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2192 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2194 if (!face
->file
) continue;
2195 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2196 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2198 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2199 release_face( face
);
2203 release_family( family
);
2208 static void DumpFontList(void)
2213 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2214 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2215 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2216 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2218 TRACE(" %d", face
->size
.height
);
2225 /***********************************************************
2226 * The replacement list is a way to map an entire font
2227 * family onto another family. For example adding
2229 * [HKCU\Software\Wine\Fonts\Replacements]
2230 * "Wingdings"="Winedings"
2232 * would enumerate the Winedings font both as Winedings and
2233 * Wingdings. However if a real Wingdings font is present the
2234 * replacement does not take place.
2237 static void LoadReplaceList(void)
2240 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2244 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2245 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2247 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2248 &valuelen
, &datalen
, NULL
, NULL
);
2250 valuelen
++; /* returned value doesn't include room for '\0' */
2251 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2252 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2256 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2257 &dlen
) == ERROR_SUCCESS
) {
2258 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2259 /* "NewName"="Oldname" */
2260 if(!find_family_from_any_name(value
))
2262 Family
* const family
= find_family_from_any_name(data
);
2265 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2266 if (new_family
!= NULL
)
2268 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2269 new_family
->FamilyName
= strdupW(value
);
2270 new_family
->EnglishName
= NULL
;
2271 list_init(&new_family
->faces
);
2272 new_family
->replacement
= &family
->faces
;
2273 list_add_tail(&font_list
, &new_family
->entry
);
2278 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2283 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2285 /* reset dlen and vlen */
2289 HeapFree(GetProcessHeap(), 0, data
);
2290 HeapFree(GetProcessHeap(), 0, value
);
2295 static const WCHAR
*font_links_list
[] =
2297 Lucida_Sans_Unicode
,
2298 Microsoft_Sans_Serif
,
2302 static const struct font_links_defaults_list
2304 /* Keyed off substitution for "MS Shell Dlg" */
2305 const WCHAR
*shelldlg
;
2306 /* Maximum of four substitutes, plus terminating NULL pointer */
2307 const WCHAR
*substitutes
[5];
2308 } font_links_defaults_list
[] =
2310 /* Non East-Asian */
2311 { Tahoma
, /* FIXME unverified ordering */
2312 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2314 /* Below lists are courtesy of
2315 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2319 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2321 /* Chinese Simplified */
2323 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2327 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2329 /* Chinese Traditional */
2331 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2336 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2338 SYSTEM_LINKS
*font_link
;
2340 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2342 if(!strcmpiW(font_link
->font_name
, name
))
2349 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2360 SYSTEM_LINKS
*font_link
;
2362 psub
= get_font_subst(&font_subst_list
, name
, -1);
2363 /* Don't store fonts that are only substitutes for other fonts */
2366 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2370 font_link
= find_font_link(name
);
2371 if (font_link
== NULL
)
2373 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2374 font_link
->font_name
= strdupW(name
);
2375 list_init(&font_link
->links
);
2376 list_add_tail(&system_links
, &font_link
->entry
);
2379 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2380 for (i
= 0; values
[i
] != NULL
; i
++)
2382 const struct list
*face_list
;
2383 CHILD_FONT
*child_font
;
2386 if (!strcmpiW(name
,value
))
2388 psub
= get_font_subst(&font_subst_list
, value
, -1);
2390 value
= psub
->to
.name
;
2391 family
= find_family_from_name(value
);
2395 /* Use first extant filename for this Family */
2396 face_list
= get_face_list_from_family(family
);
2397 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2401 file
= strrchrW(face
->file
, '/');
2410 face
= find_face_from_filename(file
, value
);
2413 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2417 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2418 child_font
->face
= face
;
2419 child_font
->font
= NULL
;
2420 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2421 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2422 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2423 child_font
->face
->face_index
);
2424 list_add_tail(&font_link
->links
, &child_font
->entry
);
2426 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2432 /*************************************************************
2435 static BOOL
init_system_links(void)
2439 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2440 WCHAR
*value
, *data
;
2441 WCHAR
*entry
, *next
;
2442 SYSTEM_LINKS
*font_link
, *system_font_link
;
2443 CHILD_FONT
*child_font
;
2444 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2445 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2446 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2451 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2453 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2454 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2455 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2456 val_len
= max_val
+ 1;
2457 data_len
= max_data
;
2459 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2461 psub
= get_font_subst(&font_subst_list
, value
, -1);
2462 /* Don't store fonts that are only substitutes for other fonts */
2465 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2468 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2469 font_link
->font_name
= strdupW(value
);
2470 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2471 list_init(&font_link
->links
);
2472 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2475 CHILD_FONT
*child_font
;
2477 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2479 next
= entry
+ strlenW(entry
) + 1;
2481 face_name
= strchrW(entry
, ',');
2485 while(isspaceW(*face_name
))
2488 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2490 face_name
= psub
->to
.name
;
2492 face
= find_face_from_filename(entry
, face_name
);
2495 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2499 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2500 child_font
->face
= face
;
2501 child_font
->font
= NULL
;
2502 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2503 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2504 TRACE("Adding file %s index %ld\n",
2505 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2506 list_add_tail(&font_link
->links
, &child_font
->entry
);
2508 list_add_tail(&system_links
, &font_link
->entry
);
2510 val_len
= max_val
+ 1;
2511 data_len
= max_data
;
2514 HeapFree(GetProcessHeap(), 0, value
);
2515 HeapFree(GetProcessHeap(), 0, data
);
2520 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2522 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2526 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2528 const FontSubst
*psub2
;
2529 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2531 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2533 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2534 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2536 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2537 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2539 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2541 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2547 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2550 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2551 system_font_link
->font_name
= strdupW(System
);
2552 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2553 list_init(&system_font_link
->links
);
2555 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2558 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2559 child_font
->face
= face
;
2560 child_font
->font
= NULL
;
2561 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2562 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2563 TRACE("Found Tahoma in %s index %ld\n",
2564 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2565 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2567 font_link
= find_font_link(Tahoma
);
2568 if (font_link
!= NULL
)
2570 CHILD_FONT
*font_link_entry
;
2571 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2573 CHILD_FONT
*new_child
;
2574 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2575 new_child
->face
= font_link_entry
->face
;
2576 new_child
->font
= NULL
;
2577 new_child
->face
->refcount
++;
2578 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2579 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2580 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2583 list_add_tail(&system_links
, &system_font_link
->entry
);
2587 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2590 struct dirent
*dent
;
2591 char path
[MAX_PATH
];
2593 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2595 dir
= opendir(dirname
);
2597 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2600 while((dent
= readdir(dir
)) != NULL
) {
2601 struct stat statbuf
;
2603 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2606 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2608 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2610 if(stat(path
, &statbuf
) == -1)
2612 WARN("Can't stat %s\n", debugstr_a(path
));
2615 if(S_ISDIR(statbuf
.st_mode
))
2616 ReadFontDir(path
, external_fonts
);
2619 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2620 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2621 AddFontToList(path
, NULL
, 0, addfont_flags
);
2628 #ifdef SONAME_LIBFONTCONFIG
2630 static BOOL fontconfig_enabled
;
2632 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2638 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2639 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2641 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2645 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2646 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2647 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2648 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2649 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2655 static void init_fontconfig(void)
2657 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2661 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2665 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2666 LOAD_FUNCPTR(FcConfigSubstitute
);
2667 LOAD_FUNCPTR(FcFontList
);
2668 LOAD_FUNCPTR(FcFontSetDestroy
);
2669 LOAD_FUNCPTR(FcInit
);
2670 LOAD_FUNCPTR(FcObjectSetAdd
);
2671 LOAD_FUNCPTR(FcObjectSetCreate
);
2672 LOAD_FUNCPTR(FcObjectSetDestroy
);
2673 LOAD_FUNCPTR(FcPatternCreate
);
2674 LOAD_FUNCPTR(FcPatternDestroy
);
2675 LOAD_FUNCPTR(FcPatternGetBool
);
2676 LOAD_FUNCPTR(FcPatternGetInteger
);
2677 LOAD_FUNCPTR(FcPatternGetString
);
2682 FcPattern
*pattern
= pFcPatternCreate();
2683 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2684 default_aa_flags
= parse_aa_pattern( pattern
);
2685 pFcPatternDestroy( pattern
);
2686 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2687 fontconfig_enabled
= TRUE
;
2691 static void load_fontconfig_fonts(void)
2700 if (!fontconfig_enabled
) return;
2702 pat
= pFcPatternCreate();
2703 os
= pFcObjectSetCreate();
2704 pFcObjectSetAdd(os
, FC_FILE
);
2705 pFcObjectSetAdd(os
, FC_SCALABLE
);
2706 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2707 pFcObjectSetAdd(os
, FC_RGBA
);
2708 fontset
= pFcFontList(NULL
, pat
, os
);
2709 if(!fontset
) return;
2710 for(i
= 0; i
< fontset
->nfont
; i
++) {
2714 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2717 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2719 /* We're just interested in OT/TT fonts for now, so this hack just
2720 picks up the scalable fonts without extensions .pf[ab] to save time
2721 loading every other font */
2723 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2725 TRACE("not scalable\n");
2729 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2730 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2732 len
= strlen( file
);
2733 if(len
< 4) continue;
2734 ext
= &file
[ len
- 3 ];
2735 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2736 AddFontToList(file
, NULL
, 0,
2737 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2739 pFcFontSetDestroy(fontset
);
2740 pFcObjectSetDestroy(os
);
2741 pFcPatternDestroy(pat
);
2744 #elif defined(HAVE_CARBON_CARBON_H)
2746 static void load_mac_font_callback(const void *value
, void *context
)
2748 CFStringRef pathStr
= value
;
2752 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2753 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2754 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2756 TRACE("font file %s\n", path
);
2757 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2759 HeapFree(GetProcessHeap(), 0, path
);
2762 static void load_mac_fonts(void)
2764 CFStringRef removeDupesKey
;
2765 CFBooleanRef removeDupesValue
;
2766 CFDictionaryRef options
;
2767 CTFontCollectionRef col
;
2769 CFMutableSetRef paths
;
2772 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2773 removeDupesValue
= kCFBooleanTrue
;
2774 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2775 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2776 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2777 if (options
) CFRelease(options
);
2780 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2784 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2788 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2792 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2795 WARN("CFSetCreateMutable failed\n");
2800 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2802 CTFontDescriptorRef desc
;
2811 desc
= CFArrayGetValueAtIndex(descs
, i
);
2813 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2814 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2815 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2816 if (!font
) continue;
2818 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2825 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2827 if (status
!= noErr
) continue;
2829 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2832 ext
= CFURLCopyPathExtension(url
);
2835 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2836 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2845 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2847 if (!path
) continue;
2849 CFSetAddValue(paths
, path
);
2855 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2861 static char *get_data_dir_path( LPCWSTR file
)
2863 char *unix_name
= NULL
;
2864 const char *data_dir
= wine_get_data_dir();
2866 if (!data_dir
) data_dir
= wine_get_build_dir();
2870 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2872 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2873 strcpy(unix_name
, data_dir
);
2874 strcat(unix_name
, "/fonts/");
2876 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2881 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2884 char *unix_name
= get_data_dir_path( file
);
2888 EnterCriticalSection( &freetype_cs
);
2889 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2890 LeaveCriticalSection( &freetype_cs
);
2891 HeapFree(GetProcessHeap(), 0, unix_name
);
2896 static char *get_winfonts_dir_path(LPCWSTR file
)
2898 static const WCHAR slashW
[] = {'\\','\0'};
2899 WCHAR windowsdir
[MAX_PATH
];
2901 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2902 strcatW(windowsdir
, fontsW
);
2903 strcatW(windowsdir
, slashW
);
2904 strcatW(windowsdir
, file
);
2905 return wine_get_unix_file_name( windowsdir
);
2908 static void load_system_fonts(void)
2911 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2912 const WCHAR
* const *value
;
2914 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2917 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2918 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2919 strcatW(windowsdir
, fontsW
);
2920 for(value
= SystemFontValues
; *value
; value
++) {
2921 dlen
= sizeof(data
);
2922 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2926 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2927 if((unixname
= wine_get_unix_file_name(pathW
))) {
2928 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2929 HeapFree(GetProcessHeap(), 0, unixname
);
2932 load_font_from_data_dir(data
);
2939 /*************************************************************
2941 * This adds registry entries for any externally loaded fonts
2942 * (fonts from fontconfig or FontDirs). It also deletes entries
2943 * of no longer existing fonts.
2946 static void update_reg_entries(void)
2948 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2954 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2957 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2958 ERR("Can't create Windows font reg key\n");
2962 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2963 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2964 ERR("Can't create Windows font reg key\n");
2968 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2969 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2970 ERR("Can't create external font reg key\n");
2974 /* enumerate the fonts and add external ones to the two keys */
2976 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2977 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2979 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
2983 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2984 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2985 strcpyW(valueW
, face
->FullName
);
2989 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2990 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2991 strcpyW(valueW
, family
->FamilyName
);
2994 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
2995 path
= wine_get_dos_file_name( buffer
);
2996 HeapFree( GetProcessHeap(), 0, buffer
);
3000 else if ((file
= strrchrW(face
->file
, '/')))
3005 len
= strlenW(file
) + 1;
3006 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3007 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3008 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3010 HeapFree(GetProcessHeap(), 0, path
);
3011 HeapFree(GetProcessHeap(), 0, valueW
);
3015 if(external_key
) RegCloseKey(external_key
);
3016 if(win9x_key
) RegCloseKey(win9x_key
);
3017 if(winnt_key
) RegCloseKey(winnt_key
);
3021 static void delete_external_font_keys(void)
3023 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3024 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
3028 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3029 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3030 ERR("Can't create Windows font reg key\n");
3034 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3035 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3036 ERR("Can't create Windows font reg key\n");
3040 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
3041 ERR("Can't create external font reg key\n");
3045 /* Delete all external fonts added last time */
3047 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3048 &valuelen
, &datalen
, NULL
, NULL
);
3049 valuelen
++; /* returned value doesn't include room for '\0' */
3050 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3051 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3053 dlen
= datalen
* sizeof(WCHAR
);
3056 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
3057 &dlen
) == ERROR_SUCCESS
) {
3059 RegDeleteValueW(winnt_key
, valueW
);
3060 RegDeleteValueW(win9x_key
, valueW
);
3061 /* reset dlen and vlen */
3065 HeapFree(GetProcessHeap(), 0, data
);
3066 HeapFree(GetProcessHeap(), 0, valueW
);
3068 /* Delete the old external fonts key */
3069 RegCloseKey(external_key
);
3070 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
3073 if(win9x_key
) RegCloseKey(win9x_key
);
3074 if(winnt_key
) RegCloseKey(winnt_key
);
3077 /*************************************************************
3078 * WineEngAddFontResourceEx
3081 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3087 if (ft_handle
) /* do it only if we have freetype up and running */
3091 EnterCriticalSection( &freetype_cs
);
3093 if((unixname
= wine_get_unix_file_name(file
)))
3095 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3097 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3098 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
3099 HeapFree(GetProcessHeap(), 0, unixname
);
3101 if (!ret
&& !strchrW(file
, '\\')) {
3102 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3103 if ((unixname
= get_winfonts_dir_path( file
)))
3105 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3106 HeapFree(GetProcessHeap(), 0, unixname
);
3108 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3109 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3111 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3112 HeapFree(GetProcessHeap(), 0, unixname
);
3116 LeaveCriticalSection( &freetype_cs
);
3121 /*************************************************************
3122 * WineEngAddFontMemResourceEx
3125 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3129 if (ft_handle
) /* do it only if we have freetype up and running */
3131 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
3133 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
3134 memcpy(pFontCopy
, pbFont
, cbFont
);
3136 EnterCriticalSection( &freetype_cs
);
3137 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3138 LeaveCriticalSection( &freetype_cs
);
3142 TRACE("AddFontToList failed\n");
3143 HeapFree(GetProcessHeap(), 0, pFontCopy
);
3146 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3147 * For now return something unique but quite random
3149 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
3150 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
3157 /*************************************************************
3158 * WineEngRemoveFontResourceEx
3161 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3167 if (ft_handle
) /* do it only if we have freetype up and running */
3171 EnterCriticalSection( &freetype_cs
);
3173 if ((unixname
= wine_get_unix_file_name(file
)))
3175 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3177 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3178 ret
= remove_font_resource( unixname
, addfont_flags
);
3179 HeapFree(GetProcessHeap(), 0, unixname
);
3181 if (!ret
&& !strchrW(file
, '\\'))
3183 if ((unixname
= get_winfonts_dir_path( file
)))
3185 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3186 HeapFree(GetProcessHeap(), 0, unixname
);
3188 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3190 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3191 HeapFree(GetProcessHeap(), 0, unixname
);
3195 LeaveCriticalSection( &freetype_cs
);
3200 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3206 if (!font_file
) return NULL
;
3208 file_len
= strlenW( font_file
);
3210 if (font_path
&& font_path
[0])
3212 int path_len
= strlenW( font_path
);
3213 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3214 if (!fullname
) return NULL
;
3215 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3216 fullname
[path_len
] = '\\';
3217 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3221 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3222 if (!len
) return NULL
;
3223 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3224 if (!fullname
) return NULL
;
3225 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3228 unix_name
= wine_get_unix_file_name( fullname
);
3229 HeapFree( GetProcessHeap(), 0, fullname
);
3233 #include <pshpack1.h>
3236 WORD num_of_resources
;
3240 CHAR dfCopyright
[60];
3246 WORD dfInternalLeading
;
3247 WORD dfExternalLeading
;
3255 BYTE dfPitchAndFamily
;
3266 CHAR szFaceName
[LF_FACESIZE
];
3269 #include <poppack.h>
3271 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3272 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3274 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3276 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3278 WCHAR
*name
, *english_name
;
3280 NEWTEXTMETRICEXW ntm
;
3283 if (!ft_face
) return FALSE
;
3284 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3285 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3286 pFT_Done_Face( ft_face
);
3288 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3289 release_face( face
);
3290 HeapFree( GetProcessHeap(), 0, name
);
3291 HeapFree( GetProcessHeap(), 0, english_name
);
3293 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3295 memset( fd
, 0, sizeof(*fd
) );
3297 fd
->num_of_resources
= 1;
3299 fd
->dfVersion
= 0x200;
3300 fd
->dfSize
= sizeof(*fd
);
3301 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3302 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3303 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3305 fd
->dfHorizRes
= 72;
3306 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3307 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3308 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3309 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3310 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3311 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3312 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3313 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3315 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3316 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3317 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3318 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3319 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3320 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3321 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3322 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3323 fd
->dfWidthBytes
= 0;
3325 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3327 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3332 #define NE_FFLAGS_LIBMODULE 0x8000
3333 #define NE_OSFLAGS_WINDOWS 0x02
3335 static const char dos_string
[0x40] = "This is a TrueType resource file";
3336 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3338 #include <pshpack2.h>
3359 struct ne_typeinfo fontdir_type
;
3360 struct ne_nameinfo fontdir_name
;
3361 struct ne_typeinfo scalable_type
;
3362 struct ne_nameinfo scalable_name
;
3364 BYTE fontdir_res_name
[8];
3367 #include <poppack.h>
3369 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3373 DWORD size
, written
;
3375 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3376 char *font_fileA
, *last_part
, *ext
;
3377 IMAGE_DOS_HEADER dos
;
3378 IMAGE_OS2_HEADER ne
=
3380 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3382 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3383 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3385 struct rsrc_tab rsrc_tab
=
3389 { 0, 0, 0x0c50, 0x2c, 0 },
3391 { 0, 0, 0x0c50, 0x8001, 0 },
3393 { 7,'F','O','N','T','D','I','R'}
3396 memset( &dos
, 0, sizeof(dos
) );
3397 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3398 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3400 /* import name is last part\0, resident name is last part without extension
3401 non-resident name is "FONTRES:" + lfFaceName */
3403 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3404 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3405 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3407 last_part
= strrchr( font_fileA
, '\\' );
3408 if (last_part
) last_part
++;
3409 else last_part
= font_fileA
;
3410 import_name_len
= strlen( last_part
) + 1;
3412 ext
= strchr( last_part
, '.' );
3413 if (ext
) res_name_len
= ext
- last_part
;
3414 else res_name_len
= import_name_len
- 1;
3416 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3418 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3419 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3420 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3421 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3423 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3425 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3426 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3427 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3428 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3430 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3431 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3435 HeapFree( GetProcessHeap(), 0, font_fileA
);
3439 memcpy( ptr
, &dos
, sizeof(dos
) );
3440 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3441 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3443 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3444 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3446 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3447 *ptr
++ = res_name_len
;
3448 memcpy( ptr
, last_part
, res_name_len
);
3450 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3451 *ptr
++ = import_name_len
;
3452 memcpy( ptr
, last_part
, import_name_len
);
3454 ptr
= start
+ ne
.ne_nrestab
;
3455 *ptr
++ = non_res_name_len
;
3456 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3457 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3459 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3460 memcpy( ptr
, font_fileA
, font_file_len
);
3462 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3463 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3465 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3466 if (file
!= INVALID_HANDLE_VALUE
)
3468 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3470 CloseHandle( file
);
3473 HeapFree( GetProcessHeap(), 0, start
);
3474 HeapFree( GetProcessHeap(), 0, font_fileA
);
3479 /*************************************************************
3480 * WineEngCreateScalableFontResource
3483 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3484 LPCWSTR font_file
, LPCWSTR font_path
)
3486 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3487 struct fontdir fontdir
;
3490 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3491 SetLastError( ERROR_INVALID_PARAMETER
);
3494 if (hidden
) fontdir
.dfType
|= 0x80;
3495 ret
= create_fot( resource
, font_file
, &fontdir
);
3498 HeapFree( GetProcessHeap(), 0, unix_name
);
3502 static const struct nls_update_font_list
3504 UINT ansi_cp
, oem_cp
;
3505 const char *oem
, *fixed
, *system
;
3506 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3507 /* these are for font substitutes */
3508 const char *shelldlg
, *tmsrmn
;
3509 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3513 const char *from
, *to
;
3514 } arial_0
, courier_new_0
, times_new_roman_0
;
3515 } nls_update_font_list
[] =
3517 /* Latin 1 (United States) */
3518 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3519 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3520 "Tahoma","Times New Roman",
3521 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3524 /* Latin 1 (Multilingual) */
3525 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3526 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3527 "Tahoma","Times New Roman", /* FIXME unverified */
3528 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3531 /* Eastern Europe */
3532 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3533 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3534 "Tahoma","Times New Roman", /* FIXME unverified */
3535 "Fixedsys,238", "System,238",
3536 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3537 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3538 { "Arial CE,0", "Arial,238" },
3539 { "Courier New CE,0", "Courier New,238" },
3540 { "Times New Roman CE,0", "Times New Roman,238" }
3543 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3544 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3545 "Tahoma","Times New Roman", /* FIXME unverified */
3546 "Fixedsys,204", "System,204",
3547 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3548 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3549 { "Arial Cyr,0", "Arial,204" },
3550 { "Courier New Cyr,0", "Courier New,204" },
3551 { "Times New Roman Cyr,0", "Times New Roman,204" }
3554 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3555 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3556 "Tahoma","Times New Roman", /* FIXME unverified */
3557 "Fixedsys,161", "System,161",
3558 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3559 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3560 { "Arial Greek,0", "Arial,161" },
3561 { "Courier New Greek,0", "Courier New,161" },
3562 { "Times New Roman Greek,0", "Times New Roman,161" }
3565 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3566 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3567 "Tahoma","Times New Roman", /* FIXME unverified */
3568 "Fixedsys,162", "System,162",
3569 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3570 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3571 { "Arial Tur,0", "Arial,162" },
3572 { "Courier New Tur,0", "Courier New,162" },
3573 { "Times New Roman Tur,0", "Times New Roman,162" }
3576 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3577 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3578 "Tahoma","Times New Roman", /* FIXME unverified */
3579 "Fixedsys,177", "System,177",
3580 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3581 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3585 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3586 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3587 "Microsoft Sans Serif","Times New Roman",
3588 "Fixedsys,178", "System,178",
3589 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3590 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3594 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3595 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3596 "Tahoma","Times New Roman", /* FIXME unverified */
3597 "Fixedsys,186", "System,186",
3598 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3599 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3600 { "Arial Baltic,0", "Arial,186" },
3601 { "Courier New Baltic,0", "Courier New,186" },
3602 { "Times New Roman Baltic,0", "Times New Roman,186" }
3605 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3606 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3607 "Tahoma","Times New Roman", /* FIXME unverified */
3608 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3612 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3613 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3614 "Tahoma","Times New Roman", /* FIXME unverified */
3615 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3619 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3620 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3621 "MS UI Gothic","MS Serif",
3622 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3625 /* Chinese Simplified */
3626 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3627 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3628 "SimSun", "NSimSun",
3629 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3633 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3634 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3636 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3639 /* Chinese Traditional */
3640 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3641 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3642 "PMingLiU", "MingLiU",
3643 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3648 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3650 return ( ansi_cp
== 932 /* CP932 for Japanese */
3651 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3652 || ansi_cp
== 949 /* CP949 for Korean */
3653 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3656 static inline HKEY
create_fonts_NT_registry_key(void)
3660 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3661 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3665 static inline HKEY
create_fonts_9x_registry_key(void)
3669 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3670 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3674 static inline HKEY
create_config_fonts_registry_key(void)
3678 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3679 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3683 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3685 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3687 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3688 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3689 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3690 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3693 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3696 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3698 RegDeleteValueA(hkey
, name
);
3701 static void update_font_association_info(UINT current_ansi_codepage
)
3703 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3704 static const char *assoc_charset_subkey
= "Associated Charset";
3706 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3709 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3712 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3714 switch (current_ansi_codepage
)
3717 set_value_key(hsubkey
, "ANSI(00)", "NO");
3718 set_value_key(hsubkey
, "OEM(FF)", "NO");
3719 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3724 set_value_key(hsubkey
, "ANSI(00)", "YES");
3725 set_value_key(hsubkey
, "OEM(FF)", "YES");
3726 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3729 RegCloseKey(hsubkey
);
3732 /* TODO: Associated DefaultFonts */
3738 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3741 static void update_font_info(void)
3743 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3744 char buf
[40], cpbuf
[40];
3747 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3748 DWORD screen_dpi
= 96, font_dpi
= 0;
3751 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3752 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3753 &hkey
) == ERROR_SUCCESS
)
3755 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3759 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3762 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3764 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3765 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3766 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3767 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3768 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3770 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3771 if (is_dbcs_ansi_cp(ansi_cp
))
3772 use_default_fallback
= TRUE
;
3776 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3778 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3783 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3784 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3786 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3787 ansi_cp
, oem_cp
, screen_dpi
);
3789 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3790 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3793 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3797 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3798 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3800 hkey
= create_config_fonts_registry_key();
3801 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3802 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3803 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3806 hkey
= create_fonts_NT_registry_key();
3807 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3810 hkey
= create_fonts_9x_registry_key();
3811 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3814 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3816 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3817 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3818 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3819 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3821 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3822 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3823 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3824 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3825 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3826 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3827 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3828 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3830 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3831 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3832 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3840 /* Delete the FontSubstitutes from other locales */
3841 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3843 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3844 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3845 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3851 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3853 /* update locale dependent font association info in registry.
3854 update only when codepages changed, not logpixels. */
3855 if (strcmp(buf
, cpbuf
) != 0)
3856 update_font_association_info(ansi_cp
);
3859 static BOOL
init_freetype(void)
3861 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3864 "Wine cannot find the FreeType font library. To enable Wine to\n"
3865 "use TrueType fonts please install a version of FreeType greater than\n"
3866 "or equal to 2.0.5.\n"
3867 "http://www.freetype.org\n");
3871 #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;}
3873 LOAD_FUNCPTR(FT_Done_Face
)
3874 LOAD_FUNCPTR(FT_Get_Char_Index
)
3875 LOAD_FUNCPTR(FT_Get_First_Char
)
3876 LOAD_FUNCPTR(FT_Get_Next_Char
)
3877 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3878 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3879 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3880 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3881 LOAD_FUNCPTR(FT_Init_FreeType
)
3882 LOAD_FUNCPTR(FT_Library_Version
)
3883 LOAD_FUNCPTR(FT_Load_Glyph
)
3884 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3885 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3886 #ifndef FT_MULFIX_INLINED
3887 LOAD_FUNCPTR(FT_MulFix
)
3889 LOAD_FUNCPTR(FT_New_Face
)
3890 LOAD_FUNCPTR(FT_New_Memory_Face
)
3891 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3892 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
3893 LOAD_FUNCPTR(FT_Outline_Transform
)
3894 LOAD_FUNCPTR(FT_Outline_Translate
)
3895 LOAD_FUNCPTR(FT_Render_Glyph
)
3896 LOAD_FUNCPTR(FT_Select_Charmap
)
3897 LOAD_FUNCPTR(FT_Set_Charmap
)
3898 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3899 LOAD_FUNCPTR(FT_Vector_Transform
)
3900 LOAD_FUNCPTR(FT_Vector_Unit
)
3902 /* Don't warn if these ones are missing */
3903 pFT_Outline_Embolden
= wine_dlsym(ft_handle
, "FT_Outline_Embolden", NULL
, 0);
3904 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3905 #ifdef FT_LCD_FILTER_H
3906 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3909 if(pFT_Init_FreeType(&library
) != 0) {
3910 ERR("Can't init FreeType library\n");
3911 wine_dlclose(ft_handle
, NULL
, 0);
3915 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3917 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3918 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3919 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3920 ((FT_Version
.patch
) & 0x0000ff);
3922 font_driver
= &freetype_funcs
;
3927 "Wine cannot find certain functions that it needs inside the FreeType\n"
3928 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3929 "FreeType to at least version 2.1.4.\n"
3930 "http://www.freetype.org\n");
3931 wine_dlclose(ft_handle
, NULL
, 0);
3936 static void init_font_list(void)
3938 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3939 static const WCHAR pathW
[] = {'P','a','t','h',0};
3941 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3942 WCHAR windowsdir
[MAX_PATH
];
3944 const char *data_dir
;
3946 delete_external_font_keys();
3948 /* load the system bitmap fonts */
3949 load_system_fonts();
3951 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3952 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3953 strcatW(windowsdir
, fontsW
);
3954 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3956 ReadFontDir(unixname
, FALSE
);
3957 HeapFree(GetProcessHeap(), 0, unixname
);
3960 /* load the system truetype fonts */
3961 data_dir
= wine_get_data_dir();
3962 if (!data_dir
) data_dir
= wine_get_build_dir();
3963 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3965 strcpy(unixname
, data_dir
);
3966 strcat(unixname
, "/fonts/");
3967 ReadFontDir(unixname
, TRUE
);
3968 HeapFree(GetProcessHeap(), 0, unixname
);
3971 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3972 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3973 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3975 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3976 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3977 &hkey
) == ERROR_SUCCESS
)
3979 LPWSTR data
, valueW
;
3980 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3981 &valuelen
, &datalen
, NULL
, NULL
);
3983 valuelen
++; /* returned value doesn't include room for '\0' */
3984 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3985 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3988 dlen
= datalen
* sizeof(WCHAR
);
3990 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3991 &dlen
) == ERROR_SUCCESS
)
3993 if(data
[0] && (data
[1] == ':'))
3995 if((unixname
= wine_get_unix_file_name(data
)))
3997 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3998 HeapFree(GetProcessHeap(), 0, unixname
);
4001 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
4003 WCHAR pathW
[MAX_PATH
];
4004 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
4007 sprintfW(pathW
, fmtW
, windowsdir
, data
);
4008 if((unixname
= wine_get_unix_file_name(pathW
)))
4010 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4011 HeapFree(GetProcessHeap(), 0, unixname
);
4014 load_font_from_data_dir(data
);
4016 /* reset dlen and vlen */
4021 HeapFree(GetProcessHeap(), 0, data
);
4022 HeapFree(GetProcessHeap(), 0, valueW
);
4026 #ifdef SONAME_LIBFONTCONFIG
4027 load_fontconfig_fonts();
4028 #elif defined(HAVE_CARBON_CARBON_H)
4032 /* then look in any directories that we've specified in the config file */
4033 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4034 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
4040 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
4042 len
+= sizeof(WCHAR
);
4043 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
4044 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
4046 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
4047 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
4048 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
4049 TRACE( "got font path %s\n", debugstr_a(valueA
) );
4054 LPSTR next
= strchr( ptr
, ':' );
4055 if (next
) *next
++ = 0;
4056 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
4057 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
4059 strcpy( unixname
, home
);
4060 strcat( unixname
, ptr
+ 1 );
4061 ReadFontDir( unixname
, TRUE
);
4062 HeapFree( GetProcessHeap(), 0, unixname
);
4065 ReadFontDir( ptr
, TRUE
);
4068 HeapFree( GetProcessHeap(), 0, valueA
);
4070 HeapFree( GetProcessHeap(), 0, valueW
);
4076 static BOOL
move_to_front(const WCHAR
*name
)
4078 Family
*family
, *cursor2
;
4079 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
4081 if(!strcmpiW(family
->FamilyName
, name
))
4083 list_remove(&family
->entry
);
4084 list_add_head(&font_list
, &family
->entry
);
4091 static BOOL
set_default(const WCHAR
**name_list
)
4095 if (move_to_front(*name_list
)) return TRUE
;
4102 static void reorder_font_list(void)
4104 set_default( default_serif_list
);
4105 set_default( default_fixed_list
);
4106 set_default( default_sans_list
);
4109 /*************************************************************
4112 * Initialize FreeType library and create a list of available faces
4114 BOOL
WineEngInit(void)
4119 /* update locale dependent font info in registry */
4122 if(!init_freetype()) return FALSE
;
4124 #ifdef SONAME_LIBFONTCONFIG
4128 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
4130 ERR("Failed to create font mutex\n");
4133 WaitForSingleObject(font_mutex
, INFINITE
);
4135 create_font_cache_key(&hkey_font_cache
, &disposition
);
4137 if(disposition
== REG_CREATED_NEW_KEY
)
4140 load_font_list_from_cache(hkey_font_cache
);
4142 reorder_font_list();
4149 if(disposition
== REG_CREATED_NEW_KEY
)
4150 update_reg_entries();
4152 init_system_links();
4154 ReleaseMutex(font_mutex
);
4159 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
4162 TT_HoriHeader
*pHori
;
4165 const LONG MAX_PPEM
= (1 << 16) - 1;
4167 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4168 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4170 if(height
== 0) height
= 16;
4172 /* Calc. height of EM square:
4174 * For +ve lfHeight we have
4175 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4176 * Re-arranging gives:
4177 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4179 * For -ve lfHeight we have
4181 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4182 * with il = winAscent + winDescent - units_per_em]
4187 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
4188 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4189 pHori
->Ascender
- pHori
->Descender
);
4191 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4192 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
4193 if(ppem
> MAX_PPEM
) {
4194 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4198 else if(height
>= -MAX_PPEM
)
4201 WARN("Ignoring too large height %d\n", height
);
4208 static struct font_mapping
*map_font_file( const char *name
)
4210 struct font_mapping
*mapping
;
4214 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4215 if (fstat( fd
, &st
) == -1) goto error
;
4217 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4219 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4221 mapping
->refcount
++;
4226 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4229 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4232 if (mapping
->data
== MAP_FAILED
)
4234 HeapFree( GetProcessHeap(), 0, mapping
);
4237 mapping
->refcount
= 1;
4238 mapping
->dev
= st
.st_dev
;
4239 mapping
->ino
= st
.st_ino
;
4240 mapping
->size
= st
.st_size
;
4241 list_add_tail( &mappings_list
, &mapping
->entry
);
4249 static void unmap_font_file( struct font_mapping
*mapping
)
4251 if (!--mapping
->refcount
)
4253 list_remove( &mapping
->entry
);
4254 munmap( mapping
->data
, mapping
->size
);
4255 HeapFree( GetProcessHeap(), 0, mapping
);
4259 static LONG
load_VDMX(GdiFont
*, LONG
);
4261 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4268 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4272 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4273 font
->mapping
= map_font_file( filename
);
4274 HeapFree( GetProcessHeap(), 0, filename
);
4277 WARN("failed to map %s\n", debugstr_w(face
->file
));
4280 data_ptr
= font
->mapping
->data
;
4281 data_size
= font
->mapping
->size
;
4285 data_ptr
= face
->font_data_ptr
;
4286 data_size
= face
->font_data_size
;
4289 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4291 ERR("FT_New_Face rets %d\n", err
);
4295 /* set it here, as load_VDMX needs it */
4296 font
->ft_face
= ft_face
;
4298 if(FT_IS_SCALABLE(ft_face
)) {
4299 /* load the VDMX table if we have one */
4300 font
->ppem
= load_VDMX(font
, height
);
4302 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4303 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4305 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4306 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4308 font
->ppem
= height
;
4309 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4310 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4316 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4318 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4319 a single face with the requested charset. The idea is to check if
4320 the selected font supports the current ANSI codepage, if it does
4321 return the corresponding charset, else return the first charset */
4324 int acp
= GetACP(), i
;
4328 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4330 const SYSTEM_LINKS
*font_link
;
4332 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4333 return csi
.ciCharset
;
4335 font_link
= find_font_link(family_name
);
4336 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4337 return csi
.ciCharset
;
4340 for(i
= 0; i
< 32; i
++) {
4342 if(face
->fs
.fsCsb
[0] & fs0
) {
4343 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4345 return csi
.ciCharset
;
4348 FIXME("TCI failing on %x\n", fs0
);
4352 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4353 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4355 return DEFAULT_CHARSET
;
4358 static GdiFont
*alloc_font(void)
4360 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4363 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4364 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4366 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4367 ret
->total_kern_pairs
= (DWORD
)-1;
4368 ret
->kern_pairs
= NULL
;
4369 list_init(&ret
->child_fonts
);
4373 static void free_font(GdiFont
*font
)
4375 CHILD_FONT
*child
, *child_next
;
4378 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4380 list_remove(&child
->entry
);
4382 free_font(child
->font
);
4383 release_face( child
->face
);
4384 HeapFree(GetProcessHeap(), 0, child
);
4387 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4388 if (font
->mapping
) unmap_font_file( font
->mapping
);
4389 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4390 HeapFree(GetProcessHeap(), 0, font
->potm
);
4391 HeapFree(GetProcessHeap(), 0, font
->name
);
4392 for (i
= 0; i
< font
->gmsize
; i
++)
4393 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4394 HeapFree(GetProcessHeap(), 0, font
->gm
);
4395 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4396 HeapFree(GetProcessHeap(), 0, font
);
4400 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4402 FT_Face ft_face
= font
->ft_face
;
4406 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4413 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4415 /* make sure value of len is the value freetype says it needs */
4418 FT_ULong needed
= 0;
4419 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4420 if( !err
&& needed
< len
) len
= needed
;
4422 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4425 TRACE("Can't find table %c%c%c%c\n",
4426 /* bytes were reversed */
4427 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4428 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4434 /*************************************************************
4437 * load the vdmx entry for the specified height
4440 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4441 ( ( (FT_ULong)_x4 << 24 ) | \
4442 ( (FT_ULong)_x3 << 16 ) | \
4443 ( (FT_ULong)_x2 << 8 ) | \
4446 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4461 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4465 BYTE devXRatio
, devYRatio
;
4466 USHORT numRecs
, numRatios
;
4467 DWORD result
, offset
= -1;
4471 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4473 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4476 /* FIXME: need the real device aspect ratio */
4480 numRecs
= GET_BE_WORD(hdr
[1]);
4481 numRatios
= GET_BE_WORD(hdr
[2]);
4483 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4484 for(i
= 0; i
< numRatios
; i
++) {
4487 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4488 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4491 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4493 if (!ratio
.bCharSet
) continue;
4495 if((ratio
.xRatio
== 0 &&
4496 ratio
.yStartRatio
== 0 &&
4497 ratio
.yEndRatio
== 0) ||
4498 (devXRatio
== ratio
.xRatio
&&
4499 devYRatio
>= ratio
.yStartRatio
&&
4500 devYRatio
<= ratio
.yEndRatio
))
4502 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4503 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4504 offset
= GET_BE_WORD(tmp
);
4509 if(offset
== -1) return 0;
4511 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4513 BYTE startsz
, endsz
;
4516 recs
= GET_BE_WORD(group
.recs
);
4517 startsz
= group
.startsz
;
4518 endsz
= group
.endsz
;
4520 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4522 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4523 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4524 if(result
== GDI_ERROR
) {
4525 FIXME("Failed to retrieve vTable\n");
4530 for(i
= 0; i
< recs
; i
++) {
4531 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4532 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4533 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4535 if(yMax
+ -yMin
== height
) {
4538 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4541 if(yMax
+ -yMin
> height
) {
4544 goto end
; /* failed */
4546 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4547 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4548 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4549 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4555 TRACE("ppem not found for height %d\n", height
);
4559 if(ppem
< startsz
|| ppem
> endsz
)
4565 for(i
= 0; i
< recs
; i
++) {
4567 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4569 if(yPelHeight
> ppem
)
4575 if(yPelHeight
== ppem
) {
4576 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4577 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4578 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4584 HeapFree(GetProcessHeap(), 0, vTable
);
4590 static void dump_gdi_font_list(void)
4594 TRACE("---------- Font Cache ----------\n");
4595 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4596 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4597 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4600 static void grab_font( GdiFont
*font
)
4602 if (!font
->refcount
++)
4604 list_remove( &font
->unused_entry
);
4605 unused_font_count
--;
4609 static void release_font( GdiFont
*font
)
4612 if (!--font
->refcount
)
4614 TRACE( "font %p\n", font
);
4616 /* add it to the unused list */
4617 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4618 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4620 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4621 TRACE( "freeing %p\n", font
);
4622 list_remove( &font
->entry
);
4623 list_remove( &font
->unused_entry
);
4626 else unused_font_count
++;
4628 if (TRACE_ON(font
)) dump_gdi_font_list();
4632 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4634 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4635 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4636 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4637 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4638 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4641 static void calc_hash(FONT_DESC
*pfd
)
4643 DWORD hash
= 0, *ptr
, two_chars
;
4647 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4649 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4651 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4653 pwc
= (WCHAR
*)&two_chars
;
4655 *pwc
= toupperW(*pwc
);
4657 *pwc
= toupperW(*pwc
);
4661 hash
^= !pfd
->can_use_bitmap
;
4666 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4673 fd
.can_use_bitmap
= can_use_bitmap
;
4676 /* try the in-use list */
4677 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4679 if(fontcmp(ret
, &fd
)) continue;
4680 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4681 list_remove( &ret
->entry
);
4682 list_add_head( &gdi_font_list
, &ret
->entry
);
4689 static void add_to_cache(GdiFont
*font
)
4691 static DWORD cache_num
= 1;
4693 font
->cache_num
= cache_num
++;
4694 list_add_head(&gdi_font_list
, &font
->entry
);
4695 TRACE( "font %p\n", font
);
4698 /*************************************************************
4699 * create_child_font_list
4701 static BOOL
create_child_font_list(GdiFont
*font
)
4704 SYSTEM_LINKS
*font_link
;
4705 CHILD_FONT
*font_link_entry
, *new_child
;
4709 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4710 font_name
= psub
? psub
->to
.name
: font
->name
;
4711 font_link
= find_font_link(font_name
);
4712 if (font_link
!= NULL
)
4714 TRACE("found entry in system list\n");
4715 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4717 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4718 new_child
->face
= font_link_entry
->face
;
4719 new_child
->font
= NULL
;
4720 new_child
->face
->refcount
++;
4721 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4722 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4727 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4728 * Sans Serif. This is how asian windows get default fallbacks for fonts
4730 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4731 font
->charset
!= OEM_CHARSET
&&
4732 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4734 font_link
= find_font_link(szDefaultFallbackLink
);
4735 if (font_link
!= NULL
)
4737 TRACE("found entry in default fallback list\n");
4738 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4740 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4741 new_child
->face
= font_link_entry
->face
;
4742 new_child
->font
= NULL
;
4743 new_child
->face
->refcount
++;
4744 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4745 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4754 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4756 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4758 if (pFT_Set_Charmap
)
4761 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4763 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4765 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4767 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4769 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4770 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4772 switch (ft_face
->charmaps
[i
]->platform_id
)
4775 cmap_def
= ft_face
->charmaps
[i
];
4777 case 0: /* Apple Unicode */
4778 cmap0
= ft_face
->charmaps
[i
];
4780 case 1: /* Macintosh */
4781 cmap1
= ft_face
->charmaps
[i
];
4784 cmap2
= ft_face
->charmaps
[i
];
4786 case 3: /* Microsoft */
4787 cmap3
= ft_face
->charmaps
[i
];
4792 if (cmap3
) /* prefer Microsoft cmap table */
4793 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4795 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4797 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4799 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4801 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4803 return ft_err
== FT_Err_Ok
;
4806 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4810 /*************************************************************
4813 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4814 LPCWSTR output
, const DEVMODEW
*devmode
)
4816 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4818 if (!physdev
) return FALSE
;
4819 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4824 /*************************************************************
4827 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4829 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4830 release_font( physdev
->font
);
4831 HeapFree( GetProcessHeap(), 0, physdev
);
4835 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4837 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4838 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4839 const FT_Encoding
*encs
= regular_order
;
4841 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4845 if (select_charmap( face
, *encs
)) break;
4851 #define GASP_GRIDFIT 0x01
4852 #define GASP_DOGRAY 0x02
4853 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4855 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4858 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4859 WORD
*alloced
= NULL
, *ptr
= buf
;
4860 WORD num_recs
, version
;
4864 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4865 if (size
== GDI_ERROR
) return FALSE
;
4866 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4867 if (size
> sizeof(buf
))
4869 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4870 if (!ptr
) return FALSE
;
4873 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4875 version
= GET_BE_WORD( *ptr
++ );
4876 num_recs
= GET_BE_WORD( *ptr
++ );
4878 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4880 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4886 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4887 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4890 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4894 HeapFree( GetProcessHeap(), 0, alloced
);
4898 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4900 const GSUB_ScriptList
*script
;
4901 const GSUB_Script
*deflt
= NULL
;
4903 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4905 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4906 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4908 const GSUB_Script
*scr
;
4911 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4912 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4914 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4916 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4922 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4926 const GSUB_LangSys
*Lang
;
4928 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4930 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4932 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4933 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4935 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4938 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4941 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4947 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4950 const GSUB_FeatureList
*feature
;
4951 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4953 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4954 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4956 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4957 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4959 const GSUB_Feature
*feat
;
4960 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4967 static const char* get_opentype_script(const GdiFont
*font
)
4970 * I am not sure if this is the correct way to generate our script tag
4973 switch (font
->charset
)
4975 case ANSI_CHARSET
: return "latn";
4976 case BALTIC_CHARSET
: return "latn"; /* ?? */
4977 case CHINESEBIG5_CHARSET
: return "hani";
4978 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4979 case GB2312_CHARSET
: return "hani";
4980 case GREEK_CHARSET
: return "grek";
4981 case HANGUL_CHARSET
: return "hang";
4982 case RUSSIAN_CHARSET
: return "cyrl";
4983 case SHIFTJIS_CHARSET
: return "kana";
4984 case TURKISH_CHARSET
: return "latn"; /* ?? */
4985 case VIETNAMESE_CHARSET
: return "latn";
4986 case JOHAB_CHARSET
: return "latn"; /* ?? */
4987 case ARABIC_CHARSET
: return "arab";
4988 case HEBREW_CHARSET
: return "hebr";
4989 case THAI_CHARSET
: return "thai";
4990 default: return "latn";
4994 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
4996 const GSUB_Header
*header
;
4997 const GSUB_Script
*script
;
4998 const GSUB_LangSys
*language
;
4999 const GSUB_Feature
*feature
;
5001 if (!font
->GSUB_Table
)
5004 header
= font
->GSUB_Table
;
5006 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5009 TRACE("Script not found\n");
5012 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5015 TRACE("Language not found\n");
5018 feature
= GSUB_get_feature(header
, language
, "vrt2");
5020 feature
= GSUB_get_feature(header
, language
, "vert");
5023 TRACE("vrt2/vert feature not found\n");
5029 /*************************************************************
5030 * freetype_SelectFont
5032 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5034 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5036 Face
*face
, *best
, *best_bitmap
;
5037 Family
*family
, *last_resort_family
;
5038 const struct list
*face_list
;
5039 INT height
, width
= 0;
5040 unsigned int score
= 0, new_score
;
5041 signed int diff
= 0, newdiff
;
5042 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5046 FontSubst
*psub
= NULL
;
5047 DC
*dc
= get_dc_ptr( dev
->hdc
);
5048 const SYSTEM_LINKS
*font_link
;
5050 if (!hfont
) /* notification that the font has been changed by another driver */
5052 release_font( physdev
->font
);
5053 physdev
->font
= NULL
;
5054 release_dc_ptr( dc
);
5058 GetObjectW( hfont
, sizeof(lf
), &lf
);
5059 lf
.lfWidth
= abs(lf
.lfWidth
);
5061 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5063 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5064 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5065 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5068 if(dc
->GraphicsMode
== GM_ADVANCED
)
5070 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5071 /* Try to avoid not necessary glyph transformations */
5072 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5074 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5075 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5076 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5081 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5082 font scaling abilities. */
5083 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5084 dcmat
.eM21
= dcmat
.eM12
= 0;
5085 lf
.lfOrientation
= lf
.lfEscapement
;
5086 if (dc
->vport2WorldValid
)
5088 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5089 lf
.lfOrientation
= -lf
.lfOrientation
;
5090 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5091 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5095 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5096 dcmat
.eM21
, dcmat
.eM22
);
5099 EnterCriticalSection( &freetype_cs
);
5101 /* check the cache first */
5102 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5103 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5107 TRACE("not in cache\n");
5110 ret
->font_desc
.matrix
= dcmat
;
5111 ret
->font_desc
.lf
= lf
;
5112 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5113 calc_hash(&ret
->font_desc
);
5115 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5116 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5117 original value lfCharSet. Note this is a special case for
5118 Symbol and doesn't happen at least for "Wingdings*" */
5120 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5121 lf
.lfCharSet
= SYMBOL_CHARSET
;
5123 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5124 switch(lf
.lfCharSet
) {
5125 case DEFAULT_CHARSET
:
5126 csi
.fs
.fsCsb
[0] = 0;
5129 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5130 csi
.fs
.fsCsb
[0] = 0;
5136 if(lf
.lfFaceName
[0] != '\0') {
5137 CHILD_FONT
*font_link_entry
;
5138 LPWSTR FaceName
= lf
.lfFaceName
;
5140 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5143 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5144 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5145 if (psub
->to
.charset
!= -1)
5146 lf
.lfCharSet
= psub
->to
.charset
;
5149 /* We want a match on name and charset or just name if
5150 charset was DEFAULT_CHARSET. If the latter then
5151 we fixup the returned charset later in get_nearest_charset
5152 where we'll either use the charset of the current ansi codepage
5153 or if that's unavailable the first charset that the font supports.
5155 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5156 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5157 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5159 font_link
= find_font_link(family
->FamilyName
);
5160 face_list
= get_face_list_from_family(family
);
5161 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5162 if (!(face
->scalable
|| can_use_bitmap
))
5164 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5166 if (font_link
!= NULL
&&
5167 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5169 if (!csi
.fs
.fsCsb
[0])
5175 /* Search by full face name. */
5176 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5177 face_list
= get_face_list_from_family(family
);
5178 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5179 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5180 (face
->scalable
|| can_use_bitmap
))
5182 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5184 font_link
= find_font_link(family
->FamilyName
);
5185 if (font_link
!= NULL
&&
5186 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5193 * Try check the SystemLink list first for a replacement font.
5194 * We may find good replacements there.
5196 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5198 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5199 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5201 TRACE("found entry in system list\n");
5202 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5204 const SYSTEM_LINKS
*links
;
5206 face
= font_link_entry
->face
;
5207 if (!(face
->scalable
|| can_use_bitmap
))
5209 family
= face
->family
;
5210 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5212 links
= find_font_link(family
->FamilyName
);
5213 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5220 psub
= NULL
; /* substitution is no more relevant */
5222 /* If requested charset was DEFAULT_CHARSET then try using charset
5223 corresponding to the current ansi codepage */
5224 if (!csi
.fs
.fsCsb
[0])
5227 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5228 FIXME("TCI failed on codepage %d\n", acp
);
5229 csi
.fs
.fsCsb
[0] = 0;
5231 lf
.lfCharSet
= csi
.ciCharset
;
5234 want_vertical
= (lf
.lfFaceName
[0] == '@');
5236 /* Face families are in the top 4 bits of lfPitchAndFamily,
5237 so mask with 0xF0 before testing */
5239 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5240 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5241 strcpyW(lf
.lfFaceName
, defFixed
);
5242 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5243 strcpyW(lf
.lfFaceName
, defSerif
);
5244 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5245 strcpyW(lf
.lfFaceName
, defSans
);
5247 strcpyW(lf
.lfFaceName
, defSans
);
5248 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5249 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5250 font_link
= find_font_link(family
->FamilyName
);
5251 face_list
= get_face_list_from_family(family
);
5252 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5253 if (!(face
->scalable
|| can_use_bitmap
))
5255 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5257 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5263 last_resort_family
= NULL
;
5264 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5265 font_link
= find_font_link(family
->FamilyName
);
5266 face_list
= get_face_list_from_family(family
);
5267 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5268 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5269 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5270 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5273 if(can_use_bitmap
&& !last_resort_family
)
5274 last_resort_family
= family
;
5279 if(last_resort_family
) {
5280 family
= last_resort_family
;
5281 csi
.fs
.fsCsb
[0] = 0;
5285 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5286 face_list
= get_face_list_from_family(family
);
5287 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5288 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5289 csi
.fs
.fsCsb
[0] = 0;
5290 WARN("just using first face for now\n");
5293 if(can_use_bitmap
&& !last_resort_family
)
5294 last_resort_family
= family
;
5297 if(!last_resort_family
) {
5298 FIXME("can't find a single appropriate font - bailing\n");
5304 WARN("could only find a bitmap font - this will probably look awful!\n");
5305 family
= last_resort_family
;
5306 csi
.fs
.fsCsb
[0] = 0;
5309 it
= lf
.lfItalic
? 1 : 0;
5310 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5312 height
= lf
.lfHeight
;
5314 face
= best
= best_bitmap
= NULL
;
5315 font_link
= find_font_link(family
->FamilyName
);
5316 face_list
= get_face_list_from_family(family
);
5317 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5319 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5320 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5325 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5326 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5327 new_score
= (italic
^ it
) + (bold
^ bd
);
5328 if(!best
|| new_score
<= score
)
5330 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5331 italic
, bold
, it
, bd
);
5334 if(best
->scalable
&& score
== 0) break;
5338 newdiff
= height
- (signed int)(best
->size
.height
);
5340 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5341 if(!best_bitmap
|| new_score
< score
||
5342 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5344 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5347 if(score
== 0 && diff
== 0) break;
5354 face
= best
->scalable
? best
: best_bitmap
;
5355 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5356 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5359 height
= lf
.lfHeight
;
5363 if(csi
.fs
.fsCsb
[0]) {
5364 ret
->charset
= lf
.lfCharSet
;
5365 ret
->codepage
= csi
.ciACP
;
5368 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5370 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5371 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5373 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5375 if(!face
->scalable
) {
5376 /* Windows uses integer scaling factors for bitmap fonts */
5377 INT scale
, scaled_height
;
5378 GdiFont
*cachedfont
;
5380 /* FIXME: rotation of bitmap fonts is ignored */
5381 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5383 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5384 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5385 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5386 /* As we changed the matrix, we need to search the cache for the font again,
5387 * otherwise we might explode the cache. */
5388 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5389 TRACE("Found cached font after non-scalable matrix rescale!\n");
5394 calc_hash(&ret
->font_desc
);
5396 if (height
!= 0) height
= diff
;
5397 height
+= face
->size
.height
;
5399 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5400 scaled_height
= scale
* face
->size
.height
;
5401 /* Only jump to the next height if the difference <= 25% original height */
5402 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5403 /* The jump between unscaled and doubled is delayed by 1 */
5404 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5405 ret
->scale_y
= scale
;
5407 width
= face
->size
.x_ppem
>> 6;
5408 height
= face
->size
.y_ppem
>> 6;
5412 TRACE("font scale y: %f\n", ret
->scale_y
);
5414 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5423 ret
->ntmFlags
= face
->ntmFlags
;
5425 pick_charmap( ret
->ft_face
, ret
->charset
);
5427 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5428 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5429 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5430 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5431 create_child_font_list(ret
);
5433 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5435 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5436 if (length
!= GDI_ERROR
)
5438 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5439 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5440 TRACE("Loaded GSUB table of %i bytes\n",length
);
5441 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5442 if (!ret
->vert_feature
)
5444 TRACE("Vertical feature not found\n");
5445 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5446 ret
->GSUB_Table
= NULL
;
5450 ret
->aa_flags
= HIWORD( face
->flags
);
5452 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5458 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5460 switch (lf
.lfQuality
)
5462 case NONANTIALIASED_QUALITY
:
5463 case ANTIALIASED_QUALITY
:
5464 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5466 case CLEARTYPE_QUALITY
:
5467 case CLEARTYPE_NATURAL_QUALITY
:
5469 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5470 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5472 /* fixup the antialiasing flags for that font */
5475 case WINE_GGO_HRGB_BITMAP
:
5476 case WINE_GGO_HBGR_BITMAP
:
5477 case WINE_GGO_VRGB_BITMAP
:
5478 case WINE_GGO_VBGR_BITMAP
:
5479 if (is_subpixel_rendering_enabled()) break;
5480 *aa_flags
= GGO_GRAY4_BITMAP
;
5482 case GGO_GRAY2_BITMAP
:
5483 case GGO_GRAY4_BITMAP
:
5484 case GGO_GRAY8_BITMAP
:
5485 case WINE_GGO_GRAY16_BITMAP
:
5486 if (is_hinting_enabled())
5489 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5491 TRACE( "font %s %d aa disabled by GASP\n",
5492 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5493 *aa_flags
= GGO_BITMAP
;
5498 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5499 release_font( physdev
->font
);
5500 physdev
->font
= ret
;
5502 LeaveCriticalSection( &freetype_cs
);
5503 release_dc_ptr( dc
);
5504 return ret
? hfont
: 0;
5507 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5514 id
+= IDS_FIRST_SCRIPT
;
5515 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5516 if (!rsrc
) return 0;
5517 hMem
= LoadResource( gdi32_module
, rsrc
);
5518 if (!hMem
) return 0;
5520 p
= LockResource( hMem
);
5522 while (id
--) p
+= *p
+ 1;
5524 i
= min(LF_FACESIZE
- 1, *p
);
5525 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5530 static inline BOOL
is_complex_script_ansi_cp(UINT ansi_cp
)
5532 return (ansi_cp
== 874 /* Thai */
5533 || ansi_cp
== 1255 /* Hebrew */
5534 || ansi_cp
== 1256 /* Arabic */
5538 /***************************************************
5539 * create_enum_charset_list
5541 * This function creates charset enumeration list because in DEFAULT_CHARSET
5542 * case, the ANSI codepage's charset takes precedence over other charsets.
5543 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5544 * This function works as a filter other than DEFAULT_CHARSET case.
5546 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5551 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5552 csi
.fs
.fsCsb
[0] != 0) {
5553 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5554 list
->element
[n
].charset
= csi
.ciCharset
;
5555 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5558 else { /* charset is DEFAULT_CHARSET or invalid. */
5562 /* Set the current codepage's charset as the first element. */
5564 if (!is_complex_script_ansi_cp(acp
) &&
5565 TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
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
);
5570 mask
|= csi
.fs
.fsCsb
[0];
5574 /* Fill out left elements. */
5575 for (i
= 0; i
< 32; i
++) {
5577 fs
.fsCsb
[0] = 1L << i
;
5579 if (fs
.fsCsb
[0] & mask
)
5580 continue; /* skip, already added. */
5581 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5582 continue; /* skip, this is an invalid fsCsb bit. */
5584 list
->element
[n
].mask
= fs
.fsCsb
[0];
5585 list
->element
[n
].charset
= csi
.ciCharset
;
5586 load_script_name( i
, list
->element
[n
].name
);
5587 mask
|= fs
.fsCsb
[0];
5591 /* add catch all mask for remaining bits */
5594 list
->element
[n
].mask
= ~mask
;
5595 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5596 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5605 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5606 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5611 if (face
->cached_enum_data
)
5614 *pelf
= face
->cached_enum_data
->elf
;
5615 *pntm
= face
->cached_enum_data
->ntm
;
5616 *ptype
= face
->cached_enum_data
->type
;
5620 font
= alloc_font();
5622 if(face
->scalable
) {
5626 height
= face
->size
.y_ppem
>> 6;
5627 width
= face
->size
.x_ppem
>> 6;
5629 font
->scale_y
= 1.0;
5631 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5637 font
->name
= strdupW( family_name
);
5638 font
->ntmFlags
= face
->ntmFlags
;
5640 if (get_outline_text_metrics(font
))
5642 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5644 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5645 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5646 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5648 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5649 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5651 lstrcpynW(pelf
->elfFullName
,
5652 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5654 lstrcpynW(pelf
->elfStyle
,
5655 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5660 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5662 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5663 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5664 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5666 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5668 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5670 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5671 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5674 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5675 pntm
->ntmFontSig
= face
->fs
;
5677 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5679 pelf
->elfLogFont
.lfEscapement
= 0;
5680 pelf
->elfLogFont
.lfOrientation
= 0;
5681 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5682 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5683 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5684 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5685 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5686 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5687 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5688 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5689 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5690 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5691 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5694 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5695 *ptype
|= TRUETYPE_FONTTYPE
;
5696 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5697 *ptype
|= DEVICE_FONTTYPE
;
5698 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5699 *ptype
|= RASTER_FONTTYPE
;
5701 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5702 if (face
->cached_enum_data
)
5704 face
->cached_enum_data
->elf
= *pelf
;
5705 face
->cached_enum_data
->ntm
= *pntm
;
5706 face
->cached_enum_data
->type
= *ptype
;
5712 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5715 const struct list
*face_list
;
5717 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5719 face_list
= get_face_list_from_family(family
);
5720 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5721 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5726 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5728 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5730 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5733 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5734 FONTENUMPROCW proc
, LPARAM lparam
)
5737 NEWTEXTMETRICEXW ntm
;
5741 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5742 for(i
= 0; i
< list
->total
; i
++) {
5743 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5744 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5745 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5746 i
= list
->total
; /* break out of loop after enumeration */
5750 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5751 /* use the DEFAULT_CHARSET case only if no other charset is present */
5752 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5753 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5754 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5755 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5756 if (!elf
.elfScript
[0])
5757 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5759 /* Font Replacement */
5760 if (family
!= face
->family
)
5762 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5764 strcpyW(elf
.elfFullName
, face
->FullName
);
5766 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5768 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5769 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5770 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5771 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5772 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5773 ntm
.ntmTm
.ntmFlags
);
5774 /* release section before callback (FIXME) */
5775 LeaveCriticalSection( &freetype_cs
);
5776 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5777 EnterCriticalSection( &freetype_cs
);
5782 /*************************************************************
5783 * freetype_EnumFonts
5785 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5789 const struct list
*face_list
;
5791 struct enum_charset_list enum_charsets
;
5795 lf
.lfCharSet
= DEFAULT_CHARSET
;
5796 lf
.lfPitchAndFamily
= 0;
5797 lf
.lfFaceName
[0] = 0;
5801 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5803 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5806 EnterCriticalSection( &freetype_cs
);
5807 if(plf
->lfFaceName
[0]) {
5809 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5812 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5813 debugstr_w(psub
->to
.name
));
5815 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5819 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5820 if (!family_matches(family
, plf
)) continue;
5821 face_list
= get_face_list_from_family(family
);
5822 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5823 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5824 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5828 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5829 face_list
= get_face_list_from_family(family
);
5830 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5831 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5834 LeaveCriticalSection( &freetype_cs
);
5838 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5840 pt
->x
.value
= vec
->x
>> 6;
5841 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5842 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5843 pt
->y
.value
= vec
->y
>> 6;
5844 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5845 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5849 /***************************************************
5850 * According to the MSDN documentation on WideCharToMultiByte,
5851 * certain codepages cannot set the default_used parameter.
5852 * This returns TRUE if the codepage can set that parameter, false else
5853 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5855 static BOOL
codepage_sets_default_used(UINT codepage
)
5869 * GSUB Table handling functions
5872 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5874 const GSUB_CoverageFormat1
* cf1
;
5878 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5880 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5882 TRACE("Coverage Format 1, %i glyphs\n",count
);
5883 for (i
= 0; i
< count
; i
++)
5884 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5888 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5890 const GSUB_CoverageFormat2
* cf2
;
5893 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5895 count
= GET_BE_WORD(cf2
->RangeCount
);
5896 TRACE("Coverage Format 2, %i ranges\n",count
);
5897 for (i
= 0; i
< count
; i
++)
5899 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5901 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5902 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5904 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5905 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5911 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5916 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5920 const GSUB_LookupList
*lookup
;
5921 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5923 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5924 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5926 const GSUB_LookupTable
*look
;
5927 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5928 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5929 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5930 if (GET_BE_WORD(look
->LookupType
) != 1)
5931 FIXME("We only handle SubType 1\n");
5936 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5938 const GSUB_SingleSubstFormat1
*ssf1
;
5939 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5940 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5941 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5943 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5944 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5945 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5947 TRACE(" Glyph 0x%x ->",glyph
);
5948 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5949 TRACE(" 0x%x\n",glyph
);
5954 const GSUB_SingleSubstFormat2
*ssf2
;
5958 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5959 offset
= GET_BE_WORD(ssf1
->Coverage
);
5960 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5961 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5962 TRACE(" Coverage index %i\n",index
);
5965 TRACE(" Glyph is 0x%x ->",glyph
);
5966 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5967 TRACE("0x%x\n",glyph
);
5977 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5979 const GSUB_Header
*header
;
5980 const GSUB_Feature
*feature
;
5982 if (!font
->GSUB_Table
)
5985 header
= font
->GSUB_Table
;
5986 feature
= font
->vert_feature
;
5988 return GSUB_apply_feature(header
, feature
, glyph
);
5991 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5995 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5996 WCHAR wc
= (WCHAR
)glyph
;
5998 BOOL
*default_used_pointer
;
6001 default_used_pointer
= NULL
;
6002 default_used
= FALSE
;
6003 if (codepage_sets_default_used(font
->codepage
))
6004 default_used_pointer
= &default_used
;
6005 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6007 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6008 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6013 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6014 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6018 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6020 if (glyph
< 0x100) glyph
+= 0xf000;
6021 /* there is a number of old pre-Unicode "broken" TTFs, which
6022 do have symbols at U+00XX instead of U+f0XX */
6023 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6024 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6026 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6031 /* helper for freetype_GetGlyphIndices */
6032 static FT_UInt
get_gdi_glyph_index(const GdiFont
*font
, UINT glyph
)
6034 WCHAR wc
= (WCHAR
)glyph
;
6035 BOOL default_used
= FALSE
;
6036 BOOL
*default_used_pointer
= NULL
;
6040 if(font
->ft_face
->charmap
->encoding
!= FT_ENCODING_NONE
)
6041 return get_glyph_index(font
, glyph
);
6043 if (codepage_sets_default_used(font
->codepage
))
6044 default_used_pointer
= &default_used
;
6045 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
)
6048 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6049 ret
= (unsigned char)wc
;
6054 ret
= (unsigned char)buf
;
6055 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6059 static FT_UInt
get_default_char_index(GdiFont
*font
)
6061 FT_UInt default_char
;
6063 if (FT_IS_SFNT(font
->ft_face
))
6065 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6066 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6071 get_text_metrics(font
, &textm
);
6072 default_char
= textm
.tmDefaultChar
;
6075 return default_char
;
6078 /*************************************************************
6079 * freetype_GetGlyphIndices
6081 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6083 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6086 BOOL got_default
= FALSE
;
6090 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6091 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6094 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6096 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6101 EnterCriticalSection( &freetype_cs
);
6103 for(i
= 0; i
< count
; i
++)
6105 pgi
[i
] = get_gdi_glyph_index(physdev
->font
, lpstr
[i
]);
6110 default_char
= get_default_char_index(physdev
->font
);
6113 pgi
[i
] = default_char
;
6116 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6118 LeaveCriticalSection( &freetype_cs
);
6122 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6124 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6125 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6128 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6130 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6131 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6134 static void synthesize_bold_glyph(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
6139 switch(glyph
->format
) {
6140 case FT_GLYPH_FORMAT_OUTLINE
:
6144 if(!pFT_Outline_Embolden
)
6147 strength
= MulDiv(ppem
, 1 << 6, 24);
6148 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
6150 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err
);
6154 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
6155 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
6156 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
6157 metrics
->horiBearingX
= bbox
.xMin
;
6158 metrics
->horiBearingY
= bbox
.yMax
;
6159 metrics
->horiAdvance
+= (1 << 6);
6160 metrics
->vertAdvance
+= (1 << 6);
6161 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
6162 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
6167 WARN("Emboldening format 0x%x is not supported\n", glyph
->format
);
6172 static inline BYTE
get_max_level( UINT format
)
6176 case GGO_GRAY2_BITMAP
: return 4;
6177 case GGO_GRAY4_BITMAP
: return 16;
6178 case GGO_GRAY8_BITMAP
: return 64;
6183 extern const unsigned short vertical_orientation_table
[];
6185 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6187 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[uchar
>> 8]+((uchar
>> 4) & 0x0f)]+ (uchar
& 0xf)];
6189 /* We only reach this code if typographical substitution did not occur */
6190 /* Type: U or Type: Tu */
6191 return (orientation
== 1 || orientation
== 3);
6194 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6196 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6197 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6200 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6202 FT_Face ft_face
= incoming_font
->ft_face
;
6203 GdiFont
*font
= incoming_font
;
6204 FT_Glyph_Metrics metrics
;
6205 FT_UInt glyph_index
;
6206 DWORD width
, height
, pitch
, needed
= 0;
6207 FT_Bitmap ft_bitmap
;
6209 INT left
, right
, top
= 0, bottom
= 0, adv
;
6210 INT origin_x
= 0, origin_y
= 0;
6212 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6213 double widthRatio
= 1.0;
6214 FT_Matrix transMat
= identityMat
;
6215 FT_Matrix transMatUnrotated
;
6216 FT_Matrix transMatTategaki
;
6217 BOOL needsTransform
= FALSE
;
6218 BOOL tategaki
= (font
->name
[0] == '@');
6219 BOOL vertical_metrics
;
6220 UINT original_index
;
6221 LONG avgAdvance
= 0;
6224 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6225 buflen
, buf
, lpmat
);
6227 TRACE("font transform %f %f %f %f\n",
6228 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6229 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6231 if(format
& GGO_GLYPH_INDEX
) {
6232 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6233 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6234 as glyph index. "Treasure Adventure Game" depends on this. */
6235 glyph_index
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6236 TRACE("translate glyph index %04x -> %04x\n", glyph
, glyph_index
);
6238 glyph_index
= glyph
;
6239 original_index
= glyph_index
;
6240 format
&= ~GGO_GLYPH_INDEX
;
6241 /* TODO: Window also turns off tategaki for glyphs passed in by index
6242 if their unicode code points fall outside of the range that is
6246 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6247 ft_face
= font
->ft_face
;
6248 original_index
= glyph_index
;
6249 if (!vert
&& tategaki
)
6250 tategaki
= check_unicode_tategaki(glyph
);
6253 if(format
& GGO_UNHINTED
) {
6254 load_flags
|= FT_LOAD_NO_HINTING
;
6255 format
&= ~GGO_UNHINTED
;
6258 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6259 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6260 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6261 font
->gmsize
* sizeof(GM
*));
6263 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6264 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6266 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6267 *abc
= FONT_GM(font
,original_index
)->abc
;
6268 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6269 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6270 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6271 return 1; /* FIXME */
6275 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6276 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6278 /* Scaling factor */
6283 get_text_metrics(font
, &tm
);
6285 widthRatio
= (double)font
->aveWidth
;
6286 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6289 widthRatio
= font
->scale_y
;
6291 /* Scaling transform */
6292 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6295 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6298 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6300 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6301 needsTransform
= TRUE
;
6304 /* Slant transform */
6305 if (font
->fake_italic
) {
6308 slantMat
.xx
= (1 << 16);
6309 slantMat
.xy
= ((1 << 16) >> 2);
6311 slantMat
.yy
= (1 << 16);
6312 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6313 needsTransform
= TRUE
;
6316 /* Rotation transform */
6317 transMatUnrotated
= transMat
;
6318 transMatTategaki
= transMat
;
6319 if(font
->orientation
|| tategaki
) {
6320 FT_Matrix rotationMat
;
6321 FT_Matrix taterotationMat
;
6324 double orient
= font
->orientation
/ 10.0;
6325 double tate_orient
= 0.f
;
6328 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6330 tate_orient
= font
->orientation
/10.0;
6334 angle
= FT_FixedFromFloat(orient
);
6335 pFT_Vector_Unit(&vecAngle
, angle
);
6336 rotationMat
.xx
= vecAngle
.x
;
6337 rotationMat
.xy
= -vecAngle
.y
;
6338 rotationMat
.yx
= -rotationMat
.xy
;
6339 rotationMat
.yy
= rotationMat
.xx
;
6341 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6346 angle
= FT_FixedFromFloat(tate_orient
);
6347 pFT_Vector_Unit(&vecAngle
, angle
);
6348 taterotationMat
.xx
= vecAngle
.x
;
6349 taterotationMat
.xy
= -vecAngle
.y
;
6350 taterotationMat
.yx
= -taterotationMat
.xy
;
6351 taterotationMat
.yy
= taterotationMat
.xx
;
6352 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6355 needsTransform
= TRUE
;
6358 /* World transform */
6359 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6362 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6363 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6364 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6365 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6366 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6367 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6368 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6369 needsTransform
= TRUE
;
6372 /* Extra transformation specified by caller */
6373 if (!is_identity_MAT2(lpmat
))
6376 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6377 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6378 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6379 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6380 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6381 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6382 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6383 needsTransform
= TRUE
;
6386 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6387 /* there is a freetype bug where vertical metrics are only
6388 properly scaled and correct in 2.4.0 or greater */
6389 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6390 vertical_metrics
= FALSE
;
6392 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6393 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6395 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6398 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6402 metrics
= ft_face
->glyph
->metrics
;
6404 synthesize_bold_glyph(ft_face
->glyph
, font
->ppem
, &metrics
);
6406 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6407 * by the text metrics. The proper behavior is to clip the glyph metrics to
6408 * fit within the maximums specified in the text metrics. */
6409 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6410 get_bitmap_text_metrics(incoming_font
)) {
6411 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6412 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6413 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6414 metrics
.horiBearingY
= top
;
6415 metrics
.height
= top
- bottom
;
6417 /* TODO: Are we supposed to clip the width as well...? */
6418 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6421 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6423 if(FT_IS_SCALABLE(incoming_font
->ft_face
) && !font
->fake_bold
) {
6425 if (get_text_metrics(incoming_font
, &tm
) &&
6426 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6427 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6429 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6430 TRACE("Fixed-pitch full-width character detected\n");
6432 avgAdvance
= 0; /* cancel this feature */
6436 if(!needsTransform
) {
6437 left
= (INT
)(metrics
.horiBearingX
) & -64;
6438 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6440 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6442 adv
= (INT
)avgAdvance
* 2;
6444 top
= (metrics
.horiBearingY
+ 63) & -64;
6445 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6446 gm
.gmCellIncX
= adv
;
6450 abc
->abcA
= origin_x
>> 6;
6451 abc
->abcB
= metrics
.width
>> 6;
6459 for(xc
= 0; xc
< 2; xc
++) {
6460 for(yc
= 0; yc
< 2; yc
++) {
6461 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6462 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6463 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6464 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6465 if(xc
== 0 && yc
== 0) {
6466 left
= right
= vec
.x
;
6467 top
= bottom
= vec
.y
;
6469 if(vec
.x
< left
) left
= vec
.x
;
6470 else if(vec
.x
> right
) right
= vec
.x
;
6471 if(vec
.y
< bottom
) bottom
= vec
.y
;
6472 else if(vec
.y
> top
) top
= vec
.y
;
6477 right
= (right
+ 63) & -64;
6478 bottom
= bottom
& -64;
6479 top
= (top
+ 63) & -64;
6481 if (tategaki
&& (font
->potm
|| get_outline_text_metrics(font
)))
6483 if (vertical_metrics
)
6484 lsb
= metrics
.horiBearingY
+ metrics
.vertBearingY
;
6486 lsb
= metrics
.vertAdvance
+ (font
->potm
->otmDescent
<< 6);
6488 vec
.y
= font
->potm
->otmDescent
<< 6;
6489 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
6490 pFT_Vector_Transform(&vec
, &transMat
);
6491 origin_x
= (vec
.x
+ left
) & -64;
6492 origin_y
= (vec
.y
+ top
+ 63) & -64;
6498 lsb
= metrics
.horiBearingX
;
6501 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6502 if (vertical_metrics
)
6503 vec
.x
= metrics
.vertAdvance
;
6505 vec
.x
= metrics
.horiAdvance
;
6507 pFT_Vector_Transform(&vec
, &transMat
);
6508 gm
.gmCellIncY
= -((vec
.y
+63) >> 6);
6509 if (!avgAdvance
|| vec
.y
)
6510 gm
.gmCellIncX
= (vec
.x
+63) >> 6;
6512 vec
.x
= incoming_font
->ntmAvgWidth
;
6514 pFT_Vector_Transform(&vec
, &transMat
);
6515 gm
.gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6518 if (vertical_metrics
)
6519 vec
.x
= metrics
.vertAdvance
;
6521 vec
.x
= metrics
.horiAdvance
;
6523 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6524 if (!avgAdvance
|| vec
.y
)
6525 adv
= (vec
.x
+63) >> 6;
6527 vec
.x
= incoming_font
->ntmAvgWidth
;
6529 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6530 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6535 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6536 abc
->abcA
= vec
.x
>> 6;
6538 vec
.x
= metrics
.width
;
6540 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6542 abc
->abcB
= vec
.x
>> 6;
6544 abc
->abcB
= -vec
.x
>> 6;
6547 width
= (right
- left
) >> 6;
6548 height
= (top
- bottom
) >> 6;
6549 gm
.gmBlackBoxX
= width
? width
: 1;
6550 gm
.gmBlackBoxY
= height
? height
: 1;
6551 gm
.gmptGlyphOrigin
.x
= origin_x
>> 6;
6552 gm
.gmptGlyphOrigin
.y
= origin_y
>> 6;
6553 if (!abc
->abcB
) abc
->abcB
= 1;
6554 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6556 TRACE("%u,%u,%s,%d,%d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
6557 wine_dbgstr_point(&gm
.gmptGlyphOrigin
),
6558 gm
.gmCellIncX
, gm
.gmCellIncY
);
6560 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6561 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6563 FONT_GM(font
,original_index
)->gm
= gm
;
6564 FONT_GM(font
,original_index
)->abc
= *abc
;
6565 FONT_GM(font
,original_index
)->init
= TRUE
;
6568 if(format
== GGO_METRICS
)
6571 return 1; /* FIXME */
6574 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6575 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6577 TRACE("loaded a bitmap\n");
6583 pitch
= ((width
+ 31) >> 5) << 2;
6584 needed
= pitch
* height
;
6586 if(!buf
|| !buflen
) break;
6587 if (!needed
) return GDI_ERROR
; /* empty glyph */
6589 switch(ft_face
->glyph
->format
) {
6590 case ft_glyph_format_bitmap
:
6592 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6593 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6594 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6596 memcpy(dst
, src
, w
);
6597 src
+= ft_face
->glyph
->bitmap
.pitch
;
6603 case ft_glyph_format_outline
:
6604 ft_bitmap
.width
= width
;
6605 ft_bitmap
.rows
= height
;
6606 ft_bitmap
.pitch
= pitch
;
6607 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6608 ft_bitmap
.buffer
= buf
;
6611 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6613 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6615 /* Note: FreeType will only set 'black' bits for us. */
6616 memset(buf
, 0, needed
);
6617 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6621 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6626 case GGO_GRAY2_BITMAP
:
6627 case GGO_GRAY4_BITMAP
:
6628 case GGO_GRAY8_BITMAP
:
6629 case WINE_GGO_GRAY16_BITMAP
:
6631 unsigned int max_level
, row
, col
;
6634 pitch
= (width
+ 3) / 4 * 4;
6635 needed
= pitch
* height
;
6637 if(!buf
|| !buflen
) break;
6638 if (!needed
) return GDI_ERROR
; /* empty glyph */
6640 max_level
= get_max_level( format
);
6642 switch(ft_face
->glyph
->format
) {
6643 case ft_glyph_format_bitmap
:
6645 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6646 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6648 memset( buf
, 0, needed
);
6650 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6651 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6652 src
+= ft_face
->glyph
->bitmap
.pitch
;
6657 case ft_glyph_format_outline
:
6659 ft_bitmap
.width
= width
;
6660 ft_bitmap
.rows
= height
;
6661 ft_bitmap
.pitch
= pitch
;
6662 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6663 ft_bitmap
.buffer
= buf
;
6666 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6668 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6670 memset(ft_bitmap
.buffer
, 0, buflen
);
6672 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6674 if (max_level
!= 255)
6676 for (row
= 0, start
= buf
; row
< height
; row
++)
6678 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6679 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6687 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6693 case WINE_GGO_HRGB_BITMAP
:
6694 case WINE_GGO_HBGR_BITMAP
:
6695 case WINE_GGO_VRGB_BITMAP
:
6696 case WINE_GGO_VBGR_BITMAP
:
6697 #ifdef FT_LCD_FILTER_H
6699 switch (ft_face
->glyph
->format
)
6701 case FT_GLYPH_FORMAT_BITMAP
:
6707 needed
= pitch
* height
;
6709 if (!buf
|| !buflen
) break;
6710 if (!needed
) return GDI_ERROR
; /* empty glyph */
6712 memset(buf
, 0, buflen
);
6714 src
= ft_face
->glyph
->bitmap
.buffer
;
6715 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6717 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6720 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6722 if ( src
[x
/ 8] & masks
[x
% 8] )
6723 ((unsigned int *)dst
)[x
] = ~0u;
6732 case FT_GLYPH_FORMAT_OUTLINE
:
6736 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6737 INT x_shift
, y_shift
;
6739 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6740 FT_Render_Mode render_mode
=
6741 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6742 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6744 if (!width
|| !height
)
6746 if (!buf
|| !buflen
) break;
6750 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6752 if ( render_mode
== FT_RENDER_MODE_LCD
)
6754 gm
.gmBlackBoxX
+= 2;
6755 gm
.gmptGlyphOrigin
.x
-= 1;
6760 gm
.gmBlackBoxY
+= 2;
6761 gm
.gmptGlyphOrigin
.y
+= 1;
6766 width
= gm
.gmBlackBoxX
;
6767 height
= gm
.gmBlackBoxY
;
6769 needed
= pitch
* height
;
6771 if (!buf
|| !buflen
) break;
6773 memset(buf
, 0, buflen
);
6775 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6777 if ( needsTransform
)
6778 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
6780 if ( pFT_Library_SetLcdFilter
)
6781 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6782 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6784 src
= ft_face
->glyph
->bitmap
.buffer
;
6785 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6786 src_width
= ft_face
->glyph
->bitmap
.width
;
6787 src_height
= ft_face
->glyph
->bitmap
.rows
;
6789 if ( render_mode
== FT_RENDER_MODE_LCD
)
6797 rgb_interval
= src_pitch
;
6802 x_shift
= ft_face
->glyph
->bitmap_left
- (left
>> 6);
6805 src
+= hmul
* -x_shift
;
6806 src_width
-= hmul
* -x_shift
;
6808 else if ( x_shift
> 0 )
6814 y_shift
= (top
>> 6) - ft_face
->glyph
->bitmap_top
;
6817 src
+= src_pitch
* vmul
* -y_shift
;
6818 src_height
-= vmul
* -y_shift
;
6820 else if ( y_shift
> 0 )
6822 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
6826 width
= min( width
, src_width
/ hmul
);
6827 height
= min( height
, src_height
/ vmul
);
6831 for ( x
= 0; x
< width
; x
++ )
6835 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6836 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6837 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6838 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6842 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6843 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6844 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6845 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6848 src
+= src_pitch
* vmul
;
6849 dst
+= pitch
/ sizeof(*dst
);
6856 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6868 int contour
, point
= 0, first_pt
;
6869 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6870 TTPOLYGONHEADER
*pph
;
6872 DWORD pph_start
, cpfx
, type
;
6874 if(buflen
== 0) buf
= NULL
;
6876 if (needsTransform
&& buf
) {
6877 pFT_Outline_Transform(outline
, &transMatTategaki
);
6880 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6881 /* Ignore contours containing one point */
6882 if(point
== outline
->contours
[contour
]) {
6888 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6891 pph
->dwType
= TT_POLYGON_TYPE
;
6892 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6894 needed
+= sizeof(*pph
);
6896 while(point
<= outline
->contours
[contour
]) {
6897 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6898 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6899 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6903 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6906 } while(point
<= outline
->contours
[contour
] &&
6907 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6908 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6909 /* At the end of a contour Windows adds the start point, but
6911 if(point
> outline
->contours
[contour
] &&
6912 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6914 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6916 } else if(point
<= outline
->contours
[contour
] &&
6917 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6918 /* add closing pt for bezier */
6920 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6928 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6931 pph
->cb
= needed
- pph_start
;
6937 /* Convert the quadratic Beziers to cubic Beziers.
6938 The parametric eqn for a cubic Bezier is, from PLRM:
6939 r(t) = at^3 + bt^2 + ct + r0
6940 with the control points:
6945 A quadratic Bezier has the form:
6946 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6948 So equating powers of t leads to:
6949 r1 = 2/3 p1 + 1/3 p0
6950 r2 = 2/3 p1 + 1/3 p2
6951 and of course r0 = p0, r3 = p2
6954 int contour
, point
= 0, first_pt
;
6955 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6956 TTPOLYGONHEADER
*pph
;
6958 DWORD pph_start
, cpfx
, type
;
6959 FT_Vector cubic_control
[4];
6960 if(buflen
== 0) buf
= NULL
;
6962 if (needsTransform
&& buf
) {
6963 pFT_Outline_Transform(outline
, &transMat
);
6966 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6968 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6971 pph
->dwType
= TT_POLYGON_TYPE
;
6972 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6974 needed
+= sizeof(*pph
);
6976 while(point
<= outline
->contours
[contour
]) {
6977 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6978 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6979 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6982 if(type
== TT_PRIM_LINE
) {
6984 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6988 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6991 /* FIXME: Possible optimization in endpoint calculation
6992 if there are two consecutive curves */
6993 cubic_control
[0] = outline
->points
[point
-1];
6994 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6995 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6996 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6997 cubic_control
[0].x
>>= 1;
6998 cubic_control
[0].y
>>= 1;
7000 if(point
+1 > outline
->contours
[contour
])
7001 cubic_control
[3] = outline
->points
[first_pt
];
7003 cubic_control
[3] = outline
->points
[point
+1];
7004 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
7005 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
7006 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
7007 cubic_control
[3].x
>>= 1;
7008 cubic_control
[3].y
>>= 1;
7011 /* r1 = 1/3 p0 + 2/3 p1
7012 r2 = 1/3 p2 + 2/3 p1 */
7013 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
7014 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
7015 cubic_control
[2] = cubic_control
[1];
7016 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
7017 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
7018 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
7019 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
7021 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
7022 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
7023 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
7028 } while(point
<= outline
->contours
[contour
] &&
7029 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
7030 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
7031 /* At the end of a contour Windows adds the start point,
7032 but only for Beziers and we've already done that.
7034 if(point
<= outline
->contours
[contour
] &&
7035 outline
->tags
[point
] & FT_Curve_Tag_On
) {
7036 /* This is the closing pt of a bezier, but we've already
7037 added it, so just inc point and carry on */
7044 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
7047 pph
->cb
= needed
- pph_start
;
7053 FIXME("Unsupported format %d\n", format
);
7060 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7062 FT_Face ft_face
= font
->ft_face
;
7063 FT_WinFNT_HeaderRec winfnt_header
;
7064 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7065 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7066 font
->potm
->otmSize
= size
;
7068 #define TM font->potm->otmTextMetrics
7069 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7071 TM
.tmHeight
= winfnt_header
.pixel_height
;
7072 TM
.tmAscent
= winfnt_header
.ascent
;
7073 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7074 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7075 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7076 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7077 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7078 TM
.tmWeight
= winfnt_header
.weight
;
7080 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7081 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7082 TM
.tmFirstChar
= winfnt_header
.first_char
;
7083 TM
.tmLastChar
= winfnt_header
.last_char
;
7084 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7085 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7086 TM
.tmItalic
= winfnt_header
.italic
;
7087 TM
.tmUnderlined
= font
->underline
;
7088 TM
.tmStruckOut
= font
->strikeout
;
7089 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7090 TM
.tmCharSet
= winfnt_header
.charset
;
7094 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7095 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7096 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7097 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7098 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7099 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7100 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7101 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7103 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7104 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7106 TM
.tmLastChar
= 255;
7107 TM
.tmDefaultChar
= 32;
7108 TM
.tmBreakChar
= 32;
7109 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7110 TM
.tmUnderlined
= font
->underline
;
7111 TM
.tmStruckOut
= font
->strikeout
;
7112 /* NB inverted meaning of TMPF_FIXED_PITCH */
7113 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
7114 TM
.tmCharSet
= font
->charset
;
7122 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7124 double scale_x
, scale_y
;
7128 scale_x
= (double)font
->aveWidth
;
7129 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7132 scale_x
= font
->scale_y
;
7134 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7135 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7137 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7138 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7140 SCALE_Y(ptm
->tmHeight
);
7141 SCALE_Y(ptm
->tmAscent
);
7142 SCALE_Y(ptm
->tmDescent
);
7143 SCALE_Y(ptm
->tmInternalLeading
);
7144 SCALE_Y(ptm
->tmExternalLeading
);
7145 SCALE_Y(ptm
->tmOverhang
);
7147 SCALE_X(ptm
->tmAveCharWidth
);
7148 SCALE_X(ptm
->tmMaxCharWidth
);
7154 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7156 double scale_x
, scale_y
;
7160 scale_x
= (double)font
->aveWidth
;
7161 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7164 scale_x
= font
->scale_y
;
7166 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7167 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7169 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7171 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7172 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7174 SCALE_Y(potm
->otmAscent
);
7175 SCALE_Y(potm
->otmDescent
);
7176 SCALE_Y(potm
->otmLineGap
);
7177 SCALE_Y(potm
->otmsCapEmHeight
);
7178 SCALE_Y(potm
->otmsXHeight
);
7179 SCALE_Y(potm
->otmrcFontBox
.top
);
7180 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7181 SCALE_X(potm
->otmrcFontBox
.left
);
7182 SCALE_X(potm
->otmrcFontBox
.right
);
7183 SCALE_Y(potm
->otmMacAscent
);
7184 SCALE_Y(potm
->otmMacDescent
);
7185 SCALE_Y(potm
->otmMacLineGap
);
7186 SCALE_X(potm
->otmptSubscriptSize
.x
);
7187 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7188 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7189 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7190 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7191 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7192 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7193 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7194 SCALE_Y(potm
->otmsStrikeoutSize
);
7195 SCALE_Y(potm
->otmsStrikeoutPosition
);
7196 SCALE_Y(potm
->otmsUnderscoreSize
);
7197 SCALE_Y(potm
->otmsUnderscorePosition
);
7203 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7207 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7209 /* Make sure that the font has sane width/height ratio */
7212 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7214 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7219 *ptm
= font
->potm
->otmTextMetrics
;
7220 scale_font_metrics(font
, ptm
);
7224 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7228 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7230 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7236 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7239 FT_Face ft_face
= font
->ft_face
;
7240 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7242 TT_HoriHeader
*pHori
;
7243 TT_Postscript
*pPost
;
7245 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7247 INT ascent
, descent
;
7249 TRACE("font=%p\n", font
);
7251 if(!FT_IS_SCALABLE(ft_face
))
7254 needed
= sizeof(*font
->potm
);
7256 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7257 family_nameW
= strdupW(font
->name
);
7259 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7262 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7263 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7265 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7267 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7270 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7271 face_nameW
= strdupW(font
->name
);
7273 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7274 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7276 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7279 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7280 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7281 full_nameW
= strdupW(fake_nameW
);
7283 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7285 /* These names should be read from the TT name table */
7287 /* length of otmpFamilyName */
7290 /* length of otmpFaceName */
7293 /* length of otmpStyleName */
7296 /* length of otmpFullName */
7300 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7302 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7304 FIXME("Can't find OS/2 table - not TT font?\n");
7308 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7310 FIXME("Can't find HHEA table - not TT font?\n");
7314 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7316 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",
7317 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7318 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7319 pOS2
->xAvgCharWidth
,
7320 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7321 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7322 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7324 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7325 font
->potm
->otmSize
= needed
;
7327 #define TM font->potm->otmTextMetrics
7329 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
7330 ascent
= pHori
->Ascender
;
7331 descent
= -pHori
->Descender
;
7333 ascent
= pOS2
->usWinAscent
;
7334 descent
= pOS2
->usWinDescent
;
7337 font
->ntmCellHeight
= ascent
+ descent
;
7338 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7340 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7341 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7344 TM
.tmAscent
= font
->yMax
;
7345 TM
.tmDescent
= -font
->yMin
;
7346 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7348 TM
.tmAscent
= SCALE_Y(ascent
);
7349 TM
.tmDescent
= SCALE_Y(descent
);
7350 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7353 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7356 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7358 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7359 ((ascent
+ descent
) -
7360 (pHori
->Ascender
- pHori
->Descender
))));
7362 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7363 if (TM
.tmAveCharWidth
== 0) {
7364 TM
.tmAveCharWidth
= 1;
7366 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7367 TM
.tmWeight
= FW_REGULAR
;
7368 if (font
->fake_bold
) {
7369 TM
.tmAveCharWidth
++;
7370 TM
.tmMaxCharWidth
++;
7371 TM
.tmWeight
= FW_BOLD
;
7375 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7377 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7378 TM
.tmWeight
= pOS2
->usWeightClass
;
7380 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7381 TM
.tmWeight
= pOS2
->usWeightClass
;
7384 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7385 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7386 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7387 * symbol range to 0 - f0ff
7390 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7395 case 1257: /* Baltic */
7396 TM
.tmLastChar
= 0xf8fd;
7399 TM
.tmLastChar
= 0xf0ff;
7401 TM
.tmBreakChar
= 0x20;
7402 TM
.tmDefaultChar
= 0x1f;
7406 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7407 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7409 if(pOS2
->usFirstCharIndex
<= 1)
7410 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7411 else if (pOS2
->usFirstCharIndex
> 0xff)
7412 TM
.tmBreakChar
= 0x20;
7414 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7415 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7417 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7418 TM
.tmUnderlined
= font
->underline
;
7419 TM
.tmStruckOut
= font
->strikeout
;
7421 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7422 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7423 (pOS2
->version
== 0xFFFFU
||
7424 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7425 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7427 TM
.tmPitchAndFamily
= 0;
7429 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7431 case PAN_FAMILY_SCRIPT
:
7432 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7435 case PAN_FAMILY_DECORATIVE
:
7436 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7441 case PAN_FAMILY_TEXT_DISPLAY
:
7442 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7443 /* which is clearly not what the panose spec says. */
7445 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7446 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7447 TM
.tmPitchAndFamily
= FF_MODERN
;
7450 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7455 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7458 case PAN_SERIF_COVE
:
7459 case PAN_SERIF_OBTUSE_COVE
:
7460 case PAN_SERIF_SQUARE_COVE
:
7461 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7462 case PAN_SERIF_SQUARE
:
7463 case PAN_SERIF_THIN
:
7464 case PAN_SERIF_BONE
:
7465 case PAN_SERIF_EXAGGERATED
:
7466 case PAN_SERIF_TRIANGLE
:
7467 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7470 case PAN_SERIF_NORMAL_SANS
:
7471 case PAN_SERIF_OBTUSE_SANS
:
7472 case PAN_SERIF_PERP_SANS
:
7473 case PAN_SERIF_FLARED
:
7474 case PAN_SERIF_ROUNDED
:
7475 TM
.tmPitchAndFamily
|= FF_SWISS
;
7482 if(FT_IS_SCALABLE(ft_face
))
7483 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7485 if(FT_IS_SFNT(ft_face
))
7487 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7488 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7490 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7493 TM
.tmCharSet
= font
->charset
;
7495 font
->potm
->otmFiller
= 0;
7496 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7497 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7498 font
->potm
->otmfsType
= pOS2
->fsType
;
7499 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7500 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7501 font
->potm
->otmItalicAngle
= 0; /* POST table */
7502 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7503 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7504 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7505 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7506 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7507 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7508 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7509 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7510 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7511 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7512 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7513 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7514 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7515 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7516 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7517 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7518 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7519 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7520 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7521 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7522 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7523 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7524 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7525 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7527 font
->potm
->otmsUnderscoreSize
= 0;
7528 font
->potm
->otmsUnderscorePosition
= 0;
7530 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7531 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7537 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7538 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7539 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7540 strcpyW((WCHAR
*)cp
, family_nameW
);
7542 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7543 strcpyW((WCHAR
*)cp
, style_nameW
);
7545 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7546 strcpyW((WCHAR
*)cp
, face_nameW
);
7548 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7549 strcpyW((WCHAR
*)cp
, full_nameW
);
7553 HeapFree(GetProcessHeap(), 0, style_nameW
);
7554 HeapFree(GetProcessHeap(), 0, family_nameW
);
7555 HeapFree(GetProcessHeap(), 0, face_nameW
);
7556 HeapFree(GetProcessHeap(), 0, full_nameW
);
7560 /*************************************************************
7561 * freetype_GetGlyphOutline
7563 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7564 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7566 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7572 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7573 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7577 EnterCriticalSection( &freetype_cs
);
7578 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7579 LeaveCriticalSection( &freetype_cs
);
7583 /*************************************************************
7584 * freetype_GetTextMetrics
7586 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7588 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7593 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7594 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7598 EnterCriticalSection( &freetype_cs
);
7599 ret
= get_text_metrics( physdev
->font
, metrics
);
7600 LeaveCriticalSection( &freetype_cs
);
7604 /*************************************************************
7605 * freetype_GetOutlineTextMetrics
7607 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7609 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7614 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7615 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7618 TRACE("font=%p\n", physdev
->font
);
7620 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7623 EnterCriticalSection( &freetype_cs
);
7625 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7627 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7629 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7630 scale_outline_font_metrics(physdev
->font
, potm
);
7632 ret
= physdev
->font
->potm
->otmSize
;
7634 LeaveCriticalSection( &freetype_cs
);
7638 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7640 child
->font
= alloc_font();
7641 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7642 if(!child
->font
->ft_face
)
7644 free_font(child
->font
);
7649 child
->font
->font_desc
= font
->font_desc
;
7650 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7651 child
->font
->orientation
= font
->orientation
;
7652 child
->font
->scale_y
= font
->scale_y
;
7653 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7654 child
->font
->base_font
= font
;
7655 TRACE("created child font %p for base %p\n", child
->font
, font
);
7659 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
7662 CHILD_FONT
*child_font
;
7665 font
= font
->base_font
;
7667 *linked_font
= font
;
7669 if((*glyph
= get_glyph_index(font
, c
)))
7672 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7673 *vert
= (o
!= *glyph
);
7677 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
7679 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7681 if(!child_font
->font
)
7682 if(!load_child_font(font
, child_font
))
7685 if(!child_font
->font
->ft_face
)
7687 g
= get_glyph_index(child_font
->font
, c
);
7689 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7693 *linked_font
= child_font
->font
;
7704 /*************************************************************
7705 * freetype_GetCharWidth
7707 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7709 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7713 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7717 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7718 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7721 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7724 EnterCriticalSection( &freetype_cs
);
7725 for(c
= firstChar
; c
<= lastChar
; c
++) {
7726 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7727 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7729 LeaveCriticalSection( &freetype_cs
);
7733 /*************************************************************
7734 * freetype_GetCharABCWidths
7736 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7738 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7741 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7745 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7746 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7749 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7752 EnterCriticalSection( &freetype_cs
);
7754 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7755 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7757 LeaveCriticalSection( &freetype_cs
);
7761 /*************************************************************
7762 * freetype_GetCharABCWidthsI
7764 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7766 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7769 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7773 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7774 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7777 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7781 EnterCriticalSection( &freetype_cs
);
7783 for(c
= 0; c
< count
; c
++, buffer
++)
7784 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7785 &gm
, buffer
, 0, NULL
, &identity
);
7787 LeaveCriticalSection( &freetype_cs
);
7791 /*************************************************************
7792 * freetype_GetTextExtentExPoint
7794 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7796 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7800 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7804 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7805 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7808 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7811 EnterCriticalSection( &freetype_cs
);
7813 for (idx
= pos
= 0; idx
< count
; idx
++)
7815 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7816 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7820 LeaveCriticalSection( &freetype_cs
);
7824 /*************************************************************
7825 * freetype_GetTextExtentExPointI
7827 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7829 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7833 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7837 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7838 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7841 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7844 EnterCriticalSection( &freetype_cs
);
7846 for (idx
= pos
= 0; idx
< count
; idx
++)
7848 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7849 &gm
, &abc
, 0, NULL
, &identity
);
7850 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7854 LeaveCriticalSection( &freetype_cs
);
7858 /*************************************************************
7859 * freetype_GetFontData
7861 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7863 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7867 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7868 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7871 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7872 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7873 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7875 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7878 /*************************************************************
7879 * freetype_GetTextFace
7881 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7884 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7888 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7889 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7892 n
= strlenW(physdev
->font
->name
) + 1;
7895 lstrcpynW(str
, physdev
->font
->name
, count
);
7901 /*************************************************************
7902 * freetype_GetTextCharsetInfo
7904 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7906 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7910 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7911 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7913 if (fs
) *fs
= physdev
->font
->fs
;
7914 return physdev
->font
->charset
;
7917 /* Retrieve a list of supported Unicode ranges for a given font.
7918 * Can be called with NULL gs to calculate the buffer size. Returns
7919 * the number of ranges found.
7921 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7923 DWORD num_ranges
= 0;
7925 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7928 FT_ULong char_code
, char_code_prev
;
7931 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7933 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7934 face
->num_glyphs
, glyph_code
, char_code
);
7936 if (!glyph_code
) return 0;
7940 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7941 gs
->ranges
[0].cGlyphs
= 0;
7942 gs
->cGlyphsSupported
= 0;
7948 if (char_code
< char_code_prev
)
7950 ERR("expected increasing char code from FT_Get_Next_Char\n");
7953 if (char_code
- char_code_prev
> 1)
7958 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7959 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7960 gs
->cGlyphsSupported
++;
7965 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7966 gs
->cGlyphsSupported
++;
7968 char_code_prev
= char_code
;
7969 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7973 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7978 /*************************************************************
7979 * freetype_GetFontUnicodeRanges
7981 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7983 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7984 DWORD size
, num_ranges
;
7988 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7989 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7992 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7993 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7996 glyphset
->cbThis
= size
;
7997 glyphset
->cRanges
= num_ranges
;
7998 glyphset
->flAccel
= 0;
8003 /*************************************************************
8004 * freetype_FontIsLinked
8006 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
8008 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8013 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
8014 return dev
->funcs
->pFontIsLinked( dev
);
8018 EnterCriticalSection( &freetype_cs
);
8019 ret
= !list_empty(&physdev
->font
->child_fonts
);
8020 LeaveCriticalSection( &freetype_cs
);
8024 /*************************************************************************
8025 * GetRasterizerCaps (GDI32.@)
8027 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8029 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8030 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
8031 lprs
->nLanguageID
= 0;
8035 /*************************************************************
8036 * freetype_GdiRealizationInfo
8038 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
8040 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8041 realization_info_t
*info
= ptr
;
8045 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
8046 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
8049 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
8052 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8055 info
->cache_num
= physdev
->font
->cache_num
;
8056 info
->unknown2
= -1;
8060 /*************************************************************************
8061 * Kerning support for TrueType fonts
8063 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8065 struct TT_kern_table
8071 struct TT_kern_subtable
8080 USHORT horizontal
: 1;
8082 USHORT cross_stream
: 1;
8083 USHORT override
: 1;
8084 USHORT reserved1
: 4;
8090 struct TT_format0_kern_subtable
8094 USHORT entrySelector
;
8105 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8106 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8107 const USHORT
*glyph_to_char
,
8108 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8111 const struct TT_kern_pair
*tt_kern_pair
;
8113 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8115 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8117 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8118 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8119 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8121 if (!kern_pair
|| !cPairs
)
8124 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8126 nPairs
= min(nPairs
, cPairs
);
8128 for (i
= 0; i
< nPairs
; i
++)
8130 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8131 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8132 /* this algorithm appears to better match what Windows does */
8133 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8134 if (kern_pair
->iKernAmount
< 0)
8136 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8137 kern_pair
->iKernAmount
-= font
->ppem
;
8139 else if (kern_pair
->iKernAmount
> 0)
8141 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8142 kern_pair
->iKernAmount
+= font
->ppem
;
8144 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8146 TRACE("left %u right %u value %d\n",
8147 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8151 TRACE("copied %u entries\n", nPairs
);
8155 /*************************************************************
8156 * freetype_GetKerningPairs
8158 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8162 const struct TT_kern_table
*tt_kern_table
;
8163 const struct TT_kern_subtable
*tt_kern_subtable
;
8165 USHORT
*glyph_to_char
;
8167 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8169 if (!(font
= physdev
->font
))
8171 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8172 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8176 EnterCriticalSection( &freetype_cs
);
8177 if (font
->total_kern_pairs
!= (DWORD
)-1)
8179 if (cPairs
&& kern_pair
)
8181 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8182 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8184 else cPairs
= font
->total_kern_pairs
;
8186 LeaveCriticalSection( &freetype_cs
);
8190 font
->total_kern_pairs
= 0;
8192 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8194 if (length
== GDI_ERROR
)
8196 TRACE("no kerning data in the font\n");
8197 LeaveCriticalSection( &freetype_cs
);
8201 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8204 WARN("Out of memory\n");
8205 LeaveCriticalSection( &freetype_cs
);
8209 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8211 /* build a glyph index to char code map */
8212 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8215 WARN("Out of memory allocating a glyph index to char code map\n");
8216 HeapFree(GetProcessHeap(), 0, buf
);
8217 LeaveCriticalSection( &freetype_cs
);
8221 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8227 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8229 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8230 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8234 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8236 /* FIXME: This doesn't match what Windows does: it does some fancy
8237 * things with duplicate glyph index to char code mappings, while
8238 * we just avoid overriding existing entries.
8240 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8241 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8243 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8250 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8251 for (n
= 0; n
<= 65535; n
++)
8252 glyph_to_char
[n
] = (USHORT
)n
;
8255 tt_kern_table
= buf
;
8256 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8257 TRACE("version %u, nTables %u\n",
8258 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8260 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8262 for (i
= 0; i
< nTables
; i
++)
8264 struct TT_kern_subtable tt_kern_subtable_copy
;
8266 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8267 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8268 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8270 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8271 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8272 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8274 /* According to the TrueType specification this is the only format
8275 * that will be properly interpreted by Windows and OS/2
8277 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8279 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8281 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8282 glyph_to_char
, NULL
, 0);
8283 font
->total_kern_pairs
+= new_chunk
;
8285 if (!font
->kern_pairs
)
8286 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8287 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8289 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8290 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8292 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8293 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8296 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8298 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8301 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8302 HeapFree(GetProcessHeap(), 0, buf
);
8304 if (cPairs
&& kern_pair
)
8306 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8307 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8309 else cPairs
= font
->total_kern_pairs
;
8311 LeaveCriticalSection( &freetype_cs
);
8315 static const struct gdi_dc_funcs freetype_funcs
=
8317 NULL
, /* pAbortDoc */
8318 NULL
, /* pAbortPath */
8319 NULL
, /* pAlphaBlend */
8320 NULL
, /* pAngleArc */
8323 NULL
, /* pBeginPath */
8324 NULL
, /* pBlendImage */
8326 NULL
, /* pCloseFigure */
8327 NULL
, /* pCreateCompatibleDC */
8328 freetype_CreateDC
, /* pCreateDC */
8329 freetype_DeleteDC
, /* pDeleteDC */
8330 NULL
, /* pDeleteObject */
8331 NULL
, /* pDeviceCapabilities */
8332 NULL
, /* pEllipse */
8334 NULL
, /* pEndPage */
8335 NULL
, /* pEndPath */
8336 freetype_EnumFonts
, /* pEnumFonts */
8337 NULL
, /* pEnumICMProfiles */
8338 NULL
, /* pExcludeClipRect */
8339 NULL
, /* pExtDeviceMode */
8340 NULL
, /* pExtEscape */
8341 NULL
, /* pExtFloodFill */
8342 NULL
, /* pExtSelectClipRgn */
8343 NULL
, /* pExtTextOut */
8344 NULL
, /* pFillPath */
8345 NULL
, /* pFillRgn */
8346 NULL
, /* pFlattenPath */
8347 freetype_FontIsLinked
, /* pFontIsLinked */
8348 NULL
, /* pFrameRgn */
8349 NULL
, /* pGdiComment */
8350 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
8351 NULL
, /* pGetBoundsRect */
8352 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8353 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8354 freetype_GetCharWidth
, /* pGetCharWidth */
8355 NULL
, /* pGetDeviceCaps */
8356 NULL
, /* pGetDeviceGammaRamp */
8357 freetype_GetFontData
, /* pGetFontData */
8358 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8359 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8360 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8361 NULL
, /* pGetICMProfile */
8362 NULL
, /* pGetImage */
8363 freetype_GetKerningPairs
, /* pGetKerningPairs */
8364 NULL
, /* pGetNearestColor */
8365 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8366 NULL
, /* pGetPixel */
8367 NULL
, /* pGetSystemPaletteEntries */
8368 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8369 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8370 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8371 freetype_GetTextFace
, /* pGetTextFace */
8372 freetype_GetTextMetrics
, /* pGetTextMetrics */
8373 NULL
, /* pGradientFill */
8374 NULL
, /* pIntersectClipRect */
8375 NULL
, /* pInvertRgn */
8377 NULL
, /* pModifyWorldTransform */
8379 NULL
, /* pOffsetClipRgn */
8380 NULL
, /* pOffsetViewportOrg */
8381 NULL
, /* pOffsetWindowOrg */
8382 NULL
, /* pPaintRgn */
8385 NULL
, /* pPolyBezier */
8386 NULL
, /* pPolyBezierTo */
8387 NULL
, /* pPolyDraw */
8388 NULL
, /* pPolyPolygon */
8389 NULL
, /* pPolyPolyline */
8390 NULL
, /* pPolygon */
8391 NULL
, /* pPolyline */
8392 NULL
, /* pPolylineTo */
8393 NULL
, /* pPutImage */
8394 NULL
, /* pRealizeDefaultPalette */
8395 NULL
, /* pRealizePalette */
8396 NULL
, /* pRectangle */
8397 NULL
, /* pResetDC */
8398 NULL
, /* pRestoreDC */
8399 NULL
, /* pRoundRect */
8401 NULL
, /* pScaleViewportExt */
8402 NULL
, /* pScaleWindowExt */
8403 NULL
, /* pSelectBitmap */
8404 NULL
, /* pSelectBrush */
8405 NULL
, /* pSelectClipPath */
8406 freetype_SelectFont
, /* pSelectFont */
8407 NULL
, /* pSelectPalette */
8408 NULL
, /* pSelectPen */
8409 NULL
, /* pSetArcDirection */
8410 NULL
, /* pSetBkColor */
8411 NULL
, /* pSetBkMode */
8412 NULL
, /* pSetDCBrushColor */
8413 NULL
, /* pSetDCPenColor */
8414 NULL
, /* pSetDIBColorTable */
8415 NULL
, /* pSetDIBitsToDevice */
8416 NULL
, /* pSetDeviceClipping */
8417 NULL
, /* pSetDeviceGammaRamp */
8418 NULL
, /* pSetLayout */
8419 NULL
, /* pSetMapMode */
8420 NULL
, /* pSetMapperFlags */
8421 NULL
, /* pSetPixel */
8422 NULL
, /* pSetPolyFillMode */
8423 NULL
, /* pSetROP2 */
8424 NULL
, /* pSetRelAbs */
8425 NULL
, /* pSetStretchBltMode */
8426 NULL
, /* pSetTextAlign */
8427 NULL
, /* pSetTextCharacterExtra */
8428 NULL
, /* pSetTextColor */
8429 NULL
, /* pSetTextJustification */
8430 NULL
, /* pSetViewportExt */
8431 NULL
, /* pSetViewportOrg */
8432 NULL
, /* pSetWindowExt */
8433 NULL
, /* pSetWindowOrg */
8434 NULL
, /* pSetWorldTransform */
8435 NULL
, /* pStartDoc */
8436 NULL
, /* pStartPage */
8437 NULL
, /* pStretchBlt */
8438 NULL
, /* pStretchDIBits */
8439 NULL
, /* pStrokeAndFillPath */
8440 NULL
, /* pStrokePath */
8441 NULL
, /* pUnrealizePalette */
8442 NULL
, /* pWidenPath */
8443 NULL
, /* wine_get_wgl_driver */
8444 GDI_PRIORITY_FONT_DRV
/* priority */
8447 #else /* HAVE_FREETYPE */
8449 /*************************************************************************/
8451 BOOL
WineEngInit(void)
8456 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8458 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8462 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8464 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8468 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8470 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8474 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8475 LPCWSTR font_file
, LPCWSTR font_path
)
8481 /*************************************************************************
8482 * GetRasterizerCaps (GDI32.@)
8484 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8486 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8488 lprs
->nLanguageID
= 0;
8492 #endif /* HAVE_FREETYPE */