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 WCHAR
*face_name
)
5715 const struct list
*face_list
;
5717 if (!strcmpiW(face_name
, 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(face_name
, face
->FullName
)) return TRUE
;
5726 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const WCHAR
*face_name
)
5728 if (!strcmpiW(face_name
, family_name
)) return TRUE
;
5730 return (face
->FullName
&& !strcmpiW(face_name
, 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]) {
5808 WCHAR
*face_name
= plf
->lfFaceName
;
5809 FontSubst
*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
));
5814 face_name
= psub
->to
.name
;
5817 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5818 if (!family_matches(family
, face_name
)) continue;
5819 face_list
= get_face_list_from_family(family
);
5820 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5821 if (!face_matches(family
->FamilyName
, face
, face_name
)) continue;
5822 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5826 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5827 face_list
= get_face_list_from_family(family
);
5828 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5829 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5832 LeaveCriticalSection( &freetype_cs
);
5836 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5838 pt
->x
.value
= vec
->x
>> 6;
5839 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5840 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5841 pt
->y
.value
= vec
->y
>> 6;
5842 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5843 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5847 /***************************************************
5848 * According to the MSDN documentation on WideCharToMultiByte,
5849 * certain codepages cannot set the default_used parameter.
5850 * This returns TRUE if the codepage can set that parameter, false else
5851 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5853 static BOOL
codepage_sets_default_used(UINT codepage
)
5867 * GSUB Table handling functions
5870 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5872 const GSUB_CoverageFormat1
* cf1
;
5876 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5878 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5880 TRACE("Coverage Format 1, %i glyphs\n",count
);
5881 for (i
= 0; i
< count
; i
++)
5882 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5886 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5888 const GSUB_CoverageFormat2
* cf2
;
5891 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5893 count
= GET_BE_WORD(cf2
->RangeCount
);
5894 TRACE("Coverage Format 2, %i ranges\n",count
);
5895 for (i
= 0; i
< count
; i
++)
5897 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5899 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5900 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5902 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5903 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5909 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5914 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5918 const GSUB_LookupList
*lookup
;
5919 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5921 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5922 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5924 const GSUB_LookupTable
*look
;
5925 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5926 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5927 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5928 if (GET_BE_WORD(look
->LookupType
) != 1)
5929 FIXME("We only handle SubType 1\n");
5934 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5936 const GSUB_SingleSubstFormat1
*ssf1
;
5937 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5938 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5939 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5941 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5942 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5943 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5945 TRACE(" Glyph 0x%x ->",glyph
);
5946 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5947 TRACE(" 0x%x\n",glyph
);
5952 const GSUB_SingleSubstFormat2
*ssf2
;
5956 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5957 offset
= GET_BE_WORD(ssf1
->Coverage
);
5958 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5959 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5960 TRACE(" Coverage index %i\n",index
);
5963 TRACE(" Glyph is 0x%x ->",glyph
);
5964 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5965 TRACE("0x%x\n",glyph
);
5975 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5977 const GSUB_Header
*header
;
5978 const GSUB_Feature
*feature
;
5980 if (!font
->GSUB_Table
)
5983 header
= font
->GSUB_Table
;
5984 feature
= font
->vert_feature
;
5986 return GSUB_apply_feature(header
, feature
, glyph
);
5989 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5993 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5994 WCHAR wc
= (WCHAR
)glyph
;
5996 BOOL
*default_used_pointer
;
5999 default_used_pointer
= NULL
;
6000 default_used
= FALSE
;
6001 if (codepage_sets_default_used(font
->codepage
))
6002 default_used_pointer
= &default_used
;
6003 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6005 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6006 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6011 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6012 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6016 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6018 if (glyph
< 0x100) glyph
+= 0xf000;
6019 /* there is a number of old pre-Unicode "broken" TTFs, which
6020 do have symbols at U+00XX instead of U+f0XX */
6021 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6022 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6024 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6029 /* helper for freetype_GetGlyphIndices */
6030 static FT_UInt
get_gdi_glyph_index(const GdiFont
*font
, UINT glyph
)
6032 WCHAR wc
= (WCHAR
)glyph
;
6033 BOOL default_used
= FALSE
;
6034 BOOL
*default_used_pointer
= NULL
;
6038 if(font
->ft_face
->charmap
->encoding
!= FT_ENCODING_NONE
)
6039 return get_glyph_index(font
, glyph
);
6041 if (codepage_sets_default_used(font
->codepage
))
6042 default_used_pointer
= &default_used
;
6043 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
)
6046 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6047 ret
= (unsigned char)wc
;
6052 ret
= (unsigned char)buf
;
6053 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6057 static FT_UInt
get_default_char_index(GdiFont
*font
)
6059 FT_UInt default_char
;
6061 if (FT_IS_SFNT(font
->ft_face
))
6063 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6064 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6069 get_text_metrics(font
, &textm
);
6070 default_char
= textm
.tmDefaultChar
;
6073 return default_char
;
6076 /*************************************************************
6077 * freetype_GetGlyphIndices
6079 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6081 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6084 BOOL got_default
= FALSE
;
6088 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6089 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6092 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6094 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6099 EnterCriticalSection( &freetype_cs
);
6101 for(i
= 0; i
< count
; i
++)
6103 pgi
[i
] = get_gdi_glyph_index(physdev
->font
, lpstr
[i
]);
6108 default_char
= get_default_char_index(physdev
->font
);
6111 pgi
[i
] = default_char
;
6114 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6116 LeaveCriticalSection( &freetype_cs
);
6120 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6122 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6123 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6126 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6128 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6129 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6132 static void synthesize_bold_glyph(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
6137 switch(glyph
->format
) {
6138 case FT_GLYPH_FORMAT_OUTLINE
:
6142 if(!pFT_Outline_Embolden
)
6145 strength
= MulDiv(ppem
, 1 << 6, 24);
6146 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
6148 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err
);
6152 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
6153 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
6154 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
6155 metrics
->horiBearingX
= bbox
.xMin
;
6156 metrics
->horiBearingY
= bbox
.yMax
;
6157 metrics
->horiAdvance
+= (1 << 6);
6158 metrics
->vertAdvance
+= (1 << 6);
6159 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
6160 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
6165 WARN("Emboldening format 0x%x is not supported\n", glyph
->format
);
6170 static inline BYTE
get_max_level( UINT format
)
6174 case GGO_GRAY2_BITMAP
: return 4;
6175 case GGO_GRAY4_BITMAP
: return 16;
6176 case GGO_GRAY8_BITMAP
: return 64;
6181 extern const unsigned short vertical_orientation_table
[];
6183 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6185 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[uchar
>> 8]+((uchar
>> 4) & 0x0f)]+ (uchar
& 0xf)];
6187 /* We only reach this code if typographical substitution did not occur */
6188 /* Type: U or Type: Tu */
6189 return (orientation
== 1 || orientation
== 3);
6192 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6194 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6195 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6198 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6200 FT_Face ft_face
= incoming_font
->ft_face
;
6201 GdiFont
*font
= incoming_font
;
6202 FT_Glyph_Metrics metrics
;
6203 FT_UInt glyph_index
;
6204 DWORD width
, height
, pitch
, needed
= 0;
6205 FT_Bitmap ft_bitmap
;
6207 INT left
, right
, top
= 0, bottom
= 0, adv
;
6208 INT origin_x
= 0, origin_y
= 0;
6210 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6211 double widthRatio
= 1.0;
6212 FT_Matrix transMat
= identityMat
;
6213 FT_Matrix transMatUnrotated
;
6214 FT_Matrix transMatTategaki
;
6215 BOOL needsTransform
= FALSE
;
6216 BOOL tategaki
= (font
->name
[0] == '@');
6217 BOOL vertical_metrics
;
6218 UINT original_index
;
6219 LONG avgAdvance
= 0;
6222 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6223 buflen
, buf
, lpmat
);
6225 TRACE("font transform %f %f %f %f\n",
6226 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6227 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6229 if(format
& GGO_GLYPH_INDEX
) {
6230 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6231 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6232 as glyph index. "Treasure Adventure Game" depends on this. */
6233 glyph_index
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6234 TRACE("translate glyph index %04x -> %04x\n", glyph
, glyph_index
);
6236 glyph_index
= glyph
;
6237 original_index
= glyph_index
;
6238 format
&= ~GGO_GLYPH_INDEX
;
6239 /* TODO: Window also turns off tategaki for glyphs passed in by index
6240 if their unicode code points fall outside of the range that is
6244 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6245 ft_face
= font
->ft_face
;
6246 original_index
= glyph_index
;
6247 if (!vert
&& tategaki
)
6248 tategaki
= check_unicode_tategaki(glyph
);
6251 if(format
& GGO_UNHINTED
) {
6252 load_flags
|= FT_LOAD_NO_HINTING
;
6253 format
&= ~GGO_UNHINTED
;
6256 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6257 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6258 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6259 font
->gmsize
* sizeof(GM
*));
6261 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6262 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6264 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6265 *abc
= FONT_GM(font
,original_index
)->abc
;
6266 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6267 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6268 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6269 return 1; /* FIXME */
6273 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6274 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6276 /* Scaling factor */
6281 get_text_metrics(font
, &tm
);
6283 widthRatio
= (double)font
->aveWidth
;
6284 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6287 widthRatio
= font
->scale_y
;
6289 /* Scaling transform */
6290 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6293 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6296 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6298 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6299 needsTransform
= TRUE
;
6302 /* Slant transform */
6303 if (font
->fake_italic
) {
6306 slantMat
.xx
= (1 << 16);
6307 slantMat
.xy
= ((1 << 16) >> 2);
6309 slantMat
.yy
= (1 << 16);
6310 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6311 needsTransform
= TRUE
;
6314 /* Rotation transform */
6315 transMatUnrotated
= transMat
;
6316 transMatTategaki
= transMat
;
6317 if(font
->orientation
|| tategaki
) {
6318 FT_Matrix rotationMat
;
6319 FT_Matrix taterotationMat
;
6322 double orient
= font
->orientation
/ 10.0;
6323 double tate_orient
= 0.f
;
6326 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6328 tate_orient
= font
->orientation
/10.0;
6332 angle
= FT_FixedFromFloat(orient
);
6333 pFT_Vector_Unit(&vecAngle
, angle
);
6334 rotationMat
.xx
= vecAngle
.x
;
6335 rotationMat
.xy
= -vecAngle
.y
;
6336 rotationMat
.yx
= -rotationMat
.xy
;
6337 rotationMat
.yy
= rotationMat
.xx
;
6339 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6344 angle
= FT_FixedFromFloat(tate_orient
);
6345 pFT_Vector_Unit(&vecAngle
, angle
);
6346 taterotationMat
.xx
= vecAngle
.x
;
6347 taterotationMat
.xy
= -vecAngle
.y
;
6348 taterotationMat
.yx
= -taterotationMat
.xy
;
6349 taterotationMat
.yy
= taterotationMat
.xx
;
6350 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6353 needsTransform
= TRUE
;
6356 /* World transform */
6357 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6360 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6361 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6362 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6363 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6364 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6365 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6366 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6367 needsTransform
= TRUE
;
6370 /* Extra transformation specified by caller */
6371 if (!is_identity_MAT2(lpmat
))
6374 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6375 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6376 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6377 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6378 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6379 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6380 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6381 needsTransform
= TRUE
;
6384 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6385 /* there is a freetype bug where vertical metrics are only
6386 properly scaled and correct in 2.4.0 or greater */
6387 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6388 vertical_metrics
= FALSE
;
6390 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6391 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6393 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6396 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6400 metrics
= ft_face
->glyph
->metrics
;
6402 synthesize_bold_glyph(ft_face
->glyph
, font
->ppem
, &metrics
);
6404 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6405 * by the text metrics. The proper behavior is to clip the glyph metrics to
6406 * fit within the maximums specified in the text metrics. */
6407 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6408 get_bitmap_text_metrics(incoming_font
)) {
6409 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6410 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6411 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6412 metrics
.horiBearingY
= top
;
6413 metrics
.height
= top
- bottom
;
6415 /* TODO: Are we supposed to clip the width as well...? */
6416 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6419 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6421 if(FT_IS_SCALABLE(incoming_font
->ft_face
) && !font
->fake_bold
) {
6423 if (get_text_metrics(incoming_font
, &tm
) &&
6424 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6425 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6427 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6428 TRACE("Fixed-pitch full-width character detected\n");
6430 avgAdvance
= 0; /* cancel this feature */
6434 if(!needsTransform
) {
6435 left
= (INT
)(metrics
.horiBearingX
) & -64;
6436 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6438 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6440 adv
= (INT
)avgAdvance
* 2;
6442 top
= (metrics
.horiBearingY
+ 63) & -64;
6443 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6444 gm
.gmCellIncX
= adv
;
6448 abc
->abcA
= origin_x
>> 6;
6449 abc
->abcB
= metrics
.width
>> 6;
6457 for(xc
= 0; xc
< 2; xc
++) {
6458 for(yc
= 0; yc
< 2; yc
++) {
6459 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6460 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6461 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6462 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6463 if(xc
== 0 && yc
== 0) {
6464 left
= right
= vec
.x
;
6465 top
= bottom
= vec
.y
;
6467 if(vec
.x
< left
) left
= vec
.x
;
6468 else if(vec
.x
> right
) right
= vec
.x
;
6469 if(vec
.y
< bottom
) bottom
= vec
.y
;
6470 else if(vec
.y
> top
) top
= vec
.y
;
6475 right
= (right
+ 63) & -64;
6476 bottom
= bottom
& -64;
6477 top
= (top
+ 63) & -64;
6479 if (tategaki
&& (font
->potm
|| get_outline_text_metrics(font
)))
6481 if (vertical_metrics
)
6482 lsb
= metrics
.horiBearingY
+ metrics
.vertBearingY
;
6484 lsb
= metrics
.vertAdvance
+ (font
->potm
->otmDescent
<< 6);
6486 vec
.y
= font
->potm
->otmDescent
<< 6;
6487 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
6488 pFT_Vector_Transform(&vec
, &transMat
);
6489 origin_x
= (vec
.x
+ left
) & -64;
6490 origin_y
= (vec
.y
+ top
+ 63) & -64;
6496 lsb
= metrics
.horiBearingX
;
6499 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6500 if (vertical_metrics
)
6501 vec
.x
= metrics
.vertAdvance
;
6503 vec
.x
= metrics
.horiAdvance
;
6505 pFT_Vector_Transform(&vec
, &transMat
);
6506 gm
.gmCellIncY
= -((vec
.y
+63) >> 6);
6507 if (!avgAdvance
|| vec
.y
)
6508 gm
.gmCellIncX
= (vec
.x
+63) >> 6;
6510 vec
.x
= incoming_font
->ntmAvgWidth
;
6512 pFT_Vector_Transform(&vec
, &transMat
);
6513 gm
.gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6516 if (vertical_metrics
)
6517 vec
.x
= metrics
.vertAdvance
;
6519 vec
.x
= metrics
.horiAdvance
;
6521 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6522 if (!avgAdvance
|| vec
.y
)
6523 adv
= (vec
.x
+63) >> 6;
6525 vec
.x
= incoming_font
->ntmAvgWidth
;
6527 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6528 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6533 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6534 abc
->abcA
= vec
.x
>> 6;
6536 vec
.x
= metrics
.width
;
6538 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6540 abc
->abcB
= vec
.x
>> 6;
6542 abc
->abcB
= -vec
.x
>> 6;
6545 width
= (right
- left
) >> 6;
6546 height
= (top
- bottom
) >> 6;
6547 gm
.gmBlackBoxX
= width
? width
: 1;
6548 gm
.gmBlackBoxY
= height
? height
: 1;
6549 gm
.gmptGlyphOrigin
.x
= origin_x
>> 6;
6550 gm
.gmptGlyphOrigin
.y
= origin_y
>> 6;
6551 if (!abc
->abcB
) abc
->abcB
= 1;
6552 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6554 TRACE("%u,%u,%s,%d,%d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
6555 wine_dbgstr_point(&gm
.gmptGlyphOrigin
),
6556 gm
.gmCellIncX
, gm
.gmCellIncY
);
6558 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6559 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6561 FONT_GM(font
,original_index
)->gm
= gm
;
6562 FONT_GM(font
,original_index
)->abc
= *abc
;
6563 FONT_GM(font
,original_index
)->init
= TRUE
;
6566 if(format
== GGO_METRICS
)
6569 return 1; /* FIXME */
6572 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6573 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6575 TRACE("loaded a bitmap\n");
6581 pitch
= ((width
+ 31) >> 5) << 2;
6582 needed
= pitch
* height
;
6584 if(!buf
|| !buflen
) break;
6585 if (!needed
) return GDI_ERROR
; /* empty glyph */
6587 switch(ft_face
->glyph
->format
) {
6588 case ft_glyph_format_bitmap
:
6590 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6591 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6592 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6594 memcpy(dst
, src
, w
);
6595 src
+= ft_face
->glyph
->bitmap
.pitch
;
6601 case ft_glyph_format_outline
:
6602 ft_bitmap
.width
= width
;
6603 ft_bitmap
.rows
= height
;
6604 ft_bitmap
.pitch
= pitch
;
6605 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6606 ft_bitmap
.buffer
= buf
;
6609 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6611 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6613 /* Note: FreeType will only set 'black' bits for us. */
6614 memset(buf
, 0, needed
);
6615 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6619 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6624 case GGO_GRAY2_BITMAP
:
6625 case GGO_GRAY4_BITMAP
:
6626 case GGO_GRAY8_BITMAP
:
6627 case WINE_GGO_GRAY16_BITMAP
:
6629 unsigned int max_level
, row
, col
;
6632 pitch
= (width
+ 3) / 4 * 4;
6633 needed
= pitch
* height
;
6635 if(!buf
|| !buflen
) break;
6636 if (!needed
) return GDI_ERROR
; /* empty glyph */
6638 max_level
= get_max_level( format
);
6640 switch(ft_face
->glyph
->format
) {
6641 case ft_glyph_format_bitmap
:
6643 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6644 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6646 memset( buf
, 0, needed
);
6648 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6649 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6650 src
+= ft_face
->glyph
->bitmap
.pitch
;
6655 case ft_glyph_format_outline
:
6657 ft_bitmap
.width
= width
;
6658 ft_bitmap
.rows
= height
;
6659 ft_bitmap
.pitch
= pitch
;
6660 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6661 ft_bitmap
.buffer
= buf
;
6664 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6666 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6668 memset(ft_bitmap
.buffer
, 0, buflen
);
6670 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6672 if (max_level
!= 255)
6674 for (row
= 0, start
= buf
; row
< height
; row
++)
6676 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6677 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6685 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6691 case WINE_GGO_HRGB_BITMAP
:
6692 case WINE_GGO_HBGR_BITMAP
:
6693 case WINE_GGO_VRGB_BITMAP
:
6694 case WINE_GGO_VBGR_BITMAP
:
6695 #ifdef FT_LCD_FILTER_H
6697 switch (ft_face
->glyph
->format
)
6699 case FT_GLYPH_FORMAT_BITMAP
:
6705 needed
= pitch
* height
;
6707 if (!buf
|| !buflen
) break;
6708 if (!needed
) return GDI_ERROR
; /* empty glyph */
6710 memset(buf
, 0, buflen
);
6712 src
= ft_face
->glyph
->bitmap
.buffer
;
6713 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6715 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6718 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6720 if ( src
[x
/ 8] & masks
[x
% 8] )
6721 ((unsigned int *)dst
)[x
] = ~0u;
6730 case FT_GLYPH_FORMAT_OUTLINE
:
6734 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6735 INT x_shift
, y_shift
;
6737 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6738 FT_Render_Mode render_mode
=
6739 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6740 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6742 if (!width
|| !height
)
6744 if (!buf
|| !buflen
) break;
6748 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6750 if ( render_mode
== FT_RENDER_MODE_LCD
)
6752 gm
.gmBlackBoxX
+= 2;
6753 gm
.gmptGlyphOrigin
.x
-= 1;
6758 gm
.gmBlackBoxY
+= 2;
6759 gm
.gmptGlyphOrigin
.y
+= 1;
6764 width
= gm
.gmBlackBoxX
;
6765 height
= gm
.gmBlackBoxY
;
6767 needed
= pitch
* height
;
6769 if (!buf
|| !buflen
) break;
6771 memset(buf
, 0, buflen
);
6773 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6775 if ( needsTransform
)
6776 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
6778 if ( pFT_Library_SetLcdFilter
)
6779 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6780 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6782 src
= ft_face
->glyph
->bitmap
.buffer
;
6783 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6784 src_width
= ft_face
->glyph
->bitmap
.width
;
6785 src_height
= ft_face
->glyph
->bitmap
.rows
;
6787 if ( render_mode
== FT_RENDER_MODE_LCD
)
6795 rgb_interval
= src_pitch
;
6800 x_shift
= ft_face
->glyph
->bitmap_left
- (left
>> 6);
6803 src
+= hmul
* -x_shift
;
6804 src_width
-= hmul
* -x_shift
;
6806 else if ( x_shift
> 0 )
6812 y_shift
= (top
>> 6) - ft_face
->glyph
->bitmap_top
;
6815 src
+= src_pitch
* vmul
* -y_shift
;
6816 src_height
-= vmul
* -y_shift
;
6818 else if ( y_shift
> 0 )
6820 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
6824 width
= min( width
, src_width
/ hmul
);
6825 height
= min( height
, src_height
/ vmul
);
6829 for ( x
= 0; x
< width
; x
++ )
6833 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6834 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6835 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6836 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6840 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6841 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6842 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6843 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6846 src
+= src_pitch
* vmul
;
6847 dst
+= pitch
/ sizeof(*dst
);
6854 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6866 int contour
, point
= 0, first_pt
;
6867 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6868 TTPOLYGONHEADER
*pph
;
6870 DWORD pph_start
, cpfx
, type
;
6872 if(buflen
== 0) buf
= NULL
;
6874 if (needsTransform
&& buf
) {
6875 pFT_Outline_Transform(outline
, &transMatTategaki
);
6878 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6879 /* Ignore contours containing one point */
6880 if(point
== outline
->contours
[contour
]) {
6886 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6889 pph
->dwType
= TT_POLYGON_TYPE
;
6890 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6892 needed
+= sizeof(*pph
);
6894 while(point
<= outline
->contours
[contour
]) {
6895 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6896 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6897 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6901 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6904 } while(point
<= outline
->contours
[contour
] &&
6905 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6906 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6907 /* At the end of a contour Windows adds the start point, but
6909 if(point
> outline
->contours
[contour
] &&
6910 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6912 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6914 } else if(point
<= outline
->contours
[contour
] &&
6915 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6916 /* add closing pt for bezier */
6918 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6926 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6929 pph
->cb
= needed
- pph_start
;
6935 /* Convert the quadratic Beziers to cubic Beziers.
6936 The parametric eqn for a cubic Bezier is, from PLRM:
6937 r(t) = at^3 + bt^2 + ct + r0
6938 with the control points:
6943 A quadratic Bezier has the form:
6944 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6946 So equating powers of t leads to:
6947 r1 = 2/3 p1 + 1/3 p0
6948 r2 = 2/3 p1 + 1/3 p2
6949 and of course r0 = p0, r3 = p2
6952 int contour
, point
= 0, first_pt
;
6953 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6954 TTPOLYGONHEADER
*pph
;
6956 DWORD pph_start
, cpfx
, type
;
6957 FT_Vector cubic_control
[4];
6958 if(buflen
== 0) buf
= NULL
;
6960 if (needsTransform
&& buf
) {
6961 pFT_Outline_Transform(outline
, &transMat
);
6964 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6966 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6969 pph
->dwType
= TT_POLYGON_TYPE
;
6970 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6972 needed
+= sizeof(*pph
);
6974 while(point
<= outline
->contours
[contour
]) {
6975 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6976 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6977 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6980 if(type
== TT_PRIM_LINE
) {
6982 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6986 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6989 /* FIXME: Possible optimization in endpoint calculation
6990 if there are two consecutive curves */
6991 cubic_control
[0] = outline
->points
[point
-1];
6992 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6993 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6994 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6995 cubic_control
[0].x
>>= 1;
6996 cubic_control
[0].y
>>= 1;
6998 if(point
+1 > outline
->contours
[contour
])
6999 cubic_control
[3] = outline
->points
[first_pt
];
7001 cubic_control
[3] = outline
->points
[point
+1];
7002 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
7003 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
7004 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
7005 cubic_control
[3].x
>>= 1;
7006 cubic_control
[3].y
>>= 1;
7009 /* r1 = 1/3 p0 + 2/3 p1
7010 r2 = 1/3 p2 + 2/3 p1 */
7011 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
7012 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
7013 cubic_control
[2] = cubic_control
[1];
7014 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
7015 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
7016 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
7017 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
7019 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
7020 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
7021 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
7026 } while(point
<= outline
->contours
[contour
] &&
7027 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
7028 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
7029 /* At the end of a contour Windows adds the start point,
7030 but only for Beziers and we've already done that.
7032 if(point
<= outline
->contours
[contour
] &&
7033 outline
->tags
[point
] & FT_Curve_Tag_On
) {
7034 /* This is the closing pt of a bezier, but we've already
7035 added it, so just inc point and carry on */
7042 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
7045 pph
->cb
= needed
- pph_start
;
7051 FIXME("Unsupported format %d\n", format
);
7058 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7060 FT_Face ft_face
= font
->ft_face
;
7061 FT_WinFNT_HeaderRec winfnt_header
;
7062 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7063 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7064 font
->potm
->otmSize
= size
;
7066 #define TM font->potm->otmTextMetrics
7067 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7069 TM
.tmHeight
= winfnt_header
.pixel_height
;
7070 TM
.tmAscent
= winfnt_header
.ascent
;
7071 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7072 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7073 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7074 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7075 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7076 TM
.tmWeight
= winfnt_header
.weight
;
7078 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7079 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7080 TM
.tmFirstChar
= winfnt_header
.first_char
;
7081 TM
.tmLastChar
= winfnt_header
.last_char
;
7082 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7083 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7084 TM
.tmItalic
= winfnt_header
.italic
;
7085 TM
.tmUnderlined
= font
->underline
;
7086 TM
.tmStruckOut
= font
->strikeout
;
7087 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7088 TM
.tmCharSet
= winfnt_header
.charset
;
7092 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7093 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7094 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7095 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7096 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7097 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7098 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7099 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7101 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7102 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7104 TM
.tmLastChar
= 255;
7105 TM
.tmDefaultChar
= 32;
7106 TM
.tmBreakChar
= 32;
7107 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7108 TM
.tmUnderlined
= font
->underline
;
7109 TM
.tmStruckOut
= font
->strikeout
;
7110 /* NB inverted meaning of TMPF_FIXED_PITCH */
7111 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
7112 TM
.tmCharSet
= font
->charset
;
7120 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7122 double scale_x
, scale_y
;
7126 scale_x
= (double)font
->aveWidth
;
7127 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7130 scale_x
= font
->scale_y
;
7132 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7133 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7135 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7136 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7138 SCALE_Y(ptm
->tmHeight
);
7139 SCALE_Y(ptm
->tmAscent
);
7140 SCALE_Y(ptm
->tmDescent
);
7141 SCALE_Y(ptm
->tmInternalLeading
);
7142 SCALE_Y(ptm
->tmExternalLeading
);
7143 SCALE_Y(ptm
->tmOverhang
);
7145 SCALE_X(ptm
->tmAveCharWidth
);
7146 SCALE_X(ptm
->tmMaxCharWidth
);
7152 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7154 double scale_x
, scale_y
;
7158 scale_x
= (double)font
->aveWidth
;
7159 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7162 scale_x
= font
->scale_y
;
7164 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7165 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7167 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7169 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7170 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7172 SCALE_Y(potm
->otmAscent
);
7173 SCALE_Y(potm
->otmDescent
);
7174 SCALE_Y(potm
->otmLineGap
);
7175 SCALE_Y(potm
->otmsCapEmHeight
);
7176 SCALE_Y(potm
->otmsXHeight
);
7177 SCALE_Y(potm
->otmrcFontBox
.top
);
7178 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7179 SCALE_X(potm
->otmrcFontBox
.left
);
7180 SCALE_X(potm
->otmrcFontBox
.right
);
7181 SCALE_Y(potm
->otmMacAscent
);
7182 SCALE_Y(potm
->otmMacDescent
);
7183 SCALE_Y(potm
->otmMacLineGap
);
7184 SCALE_X(potm
->otmptSubscriptSize
.x
);
7185 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7186 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7187 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7188 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7189 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7190 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7191 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7192 SCALE_Y(potm
->otmsStrikeoutSize
);
7193 SCALE_Y(potm
->otmsStrikeoutPosition
);
7194 SCALE_Y(potm
->otmsUnderscoreSize
);
7195 SCALE_Y(potm
->otmsUnderscorePosition
);
7201 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7205 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7207 /* Make sure that the font has sane width/height ratio */
7210 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7212 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7217 *ptm
= font
->potm
->otmTextMetrics
;
7218 scale_font_metrics(font
, ptm
);
7222 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7226 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7228 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7234 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7237 FT_Face ft_face
= font
->ft_face
;
7238 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7240 TT_HoriHeader
*pHori
;
7241 TT_Postscript
*pPost
;
7243 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7245 INT ascent
, descent
;
7247 TRACE("font=%p\n", font
);
7249 if(!FT_IS_SCALABLE(ft_face
))
7252 needed
= sizeof(*font
->potm
);
7254 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7255 family_nameW
= strdupW(font
->name
);
7257 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7260 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7261 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7263 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7265 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7268 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7269 face_nameW
= strdupW(font
->name
);
7271 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7272 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7274 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7277 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7278 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7279 full_nameW
= strdupW(fake_nameW
);
7281 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7283 /* These names should be read from the TT name table */
7285 /* length of otmpFamilyName */
7288 /* length of otmpFaceName */
7291 /* length of otmpStyleName */
7294 /* length of otmpFullName */
7298 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7300 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7302 FIXME("Can't find OS/2 table - not TT font?\n");
7306 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7308 FIXME("Can't find HHEA table - not TT font?\n");
7312 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7314 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",
7315 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7316 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7317 pOS2
->xAvgCharWidth
,
7318 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7319 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7320 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7322 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7323 font
->potm
->otmSize
= needed
;
7325 #define TM font->potm->otmTextMetrics
7327 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
7328 ascent
= pHori
->Ascender
;
7329 descent
= -pHori
->Descender
;
7331 ascent
= pOS2
->usWinAscent
;
7332 descent
= pOS2
->usWinDescent
;
7335 font
->ntmCellHeight
= ascent
+ descent
;
7336 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7338 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7339 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7342 TM
.tmAscent
= font
->yMax
;
7343 TM
.tmDescent
= -font
->yMin
;
7344 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7346 TM
.tmAscent
= SCALE_Y(ascent
);
7347 TM
.tmDescent
= SCALE_Y(descent
);
7348 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7351 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7354 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7356 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7357 ((ascent
+ descent
) -
7358 (pHori
->Ascender
- pHori
->Descender
))));
7360 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7361 if (TM
.tmAveCharWidth
== 0) {
7362 TM
.tmAveCharWidth
= 1;
7364 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7365 TM
.tmWeight
= FW_REGULAR
;
7366 if (font
->fake_bold
) {
7367 TM
.tmAveCharWidth
++;
7368 TM
.tmMaxCharWidth
++;
7369 TM
.tmWeight
= FW_BOLD
;
7373 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7375 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7376 TM
.tmWeight
= pOS2
->usWeightClass
;
7378 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7379 TM
.tmWeight
= pOS2
->usWeightClass
;
7382 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7383 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7384 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7385 * symbol range to 0 - f0ff
7388 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7393 case 1255: /* Hebrew */
7394 TM
.tmLastChar
= 0xf896;
7396 case 1257: /* Baltic */
7397 TM
.tmLastChar
= 0xf8fd;
7400 TM
.tmLastChar
= 0xf0ff;
7402 TM
.tmBreakChar
= 0x20;
7403 TM
.tmDefaultChar
= 0x1f;
7407 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7408 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7410 if(pOS2
->usFirstCharIndex
<= 1)
7411 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7412 else if (pOS2
->usFirstCharIndex
> 0xff)
7413 TM
.tmBreakChar
= 0x20;
7415 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7416 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7418 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7419 TM
.tmUnderlined
= font
->underline
;
7420 TM
.tmStruckOut
= font
->strikeout
;
7422 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7423 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7424 (pOS2
->version
== 0xFFFFU
||
7425 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7426 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7428 TM
.tmPitchAndFamily
= 0;
7430 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7432 case PAN_FAMILY_SCRIPT
:
7433 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7436 case PAN_FAMILY_DECORATIVE
:
7437 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7442 case PAN_FAMILY_TEXT_DISPLAY
:
7443 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7444 /* which is clearly not what the panose spec says. */
7446 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7447 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7448 TM
.tmPitchAndFamily
= FF_MODERN
;
7451 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7456 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7459 case PAN_SERIF_COVE
:
7460 case PAN_SERIF_OBTUSE_COVE
:
7461 case PAN_SERIF_SQUARE_COVE
:
7462 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7463 case PAN_SERIF_SQUARE
:
7464 case PAN_SERIF_THIN
:
7465 case PAN_SERIF_BONE
:
7466 case PAN_SERIF_EXAGGERATED
:
7467 case PAN_SERIF_TRIANGLE
:
7468 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7471 case PAN_SERIF_NORMAL_SANS
:
7472 case PAN_SERIF_OBTUSE_SANS
:
7473 case PAN_SERIF_PERP_SANS
:
7474 case PAN_SERIF_FLARED
:
7475 case PAN_SERIF_ROUNDED
:
7476 TM
.tmPitchAndFamily
|= FF_SWISS
;
7483 if(FT_IS_SCALABLE(ft_face
))
7484 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7486 if(FT_IS_SFNT(ft_face
))
7488 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7489 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7491 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7494 TM
.tmCharSet
= font
->charset
;
7496 font
->potm
->otmFiller
= 0;
7497 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7498 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7499 font
->potm
->otmfsType
= pOS2
->fsType
;
7500 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7501 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7502 font
->potm
->otmItalicAngle
= 0; /* POST table */
7503 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7504 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7505 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7506 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7507 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7508 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7509 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7510 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7511 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7512 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7513 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7514 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7515 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7516 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7517 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7518 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7519 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7520 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7521 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7522 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7523 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7524 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7525 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7526 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7528 font
->potm
->otmsUnderscoreSize
= 0;
7529 font
->potm
->otmsUnderscorePosition
= 0;
7531 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7532 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7538 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7539 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7540 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7541 strcpyW((WCHAR
*)cp
, family_nameW
);
7543 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7544 strcpyW((WCHAR
*)cp
, style_nameW
);
7546 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7547 strcpyW((WCHAR
*)cp
, face_nameW
);
7549 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7550 strcpyW((WCHAR
*)cp
, full_nameW
);
7554 HeapFree(GetProcessHeap(), 0, style_nameW
);
7555 HeapFree(GetProcessHeap(), 0, family_nameW
);
7556 HeapFree(GetProcessHeap(), 0, face_nameW
);
7557 HeapFree(GetProcessHeap(), 0, full_nameW
);
7561 /*************************************************************
7562 * freetype_GetGlyphOutline
7564 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7565 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7567 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7573 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7574 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7578 EnterCriticalSection( &freetype_cs
);
7579 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7580 LeaveCriticalSection( &freetype_cs
);
7584 /*************************************************************
7585 * freetype_GetTextMetrics
7587 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7589 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7594 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7595 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7599 EnterCriticalSection( &freetype_cs
);
7600 ret
= get_text_metrics( physdev
->font
, metrics
);
7601 LeaveCriticalSection( &freetype_cs
);
7605 /*************************************************************
7606 * freetype_GetOutlineTextMetrics
7608 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7610 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7615 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7616 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7619 TRACE("font=%p\n", physdev
->font
);
7621 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7624 EnterCriticalSection( &freetype_cs
);
7626 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7628 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7630 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7631 scale_outline_font_metrics(physdev
->font
, potm
);
7633 ret
= physdev
->font
->potm
->otmSize
;
7635 LeaveCriticalSection( &freetype_cs
);
7639 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7641 child
->font
= alloc_font();
7642 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7643 if(!child
->font
->ft_face
)
7645 free_font(child
->font
);
7650 child
->font
->font_desc
= font
->font_desc
;
7651 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7652 child
->font
->orientation
= font
->orientation
;
7653 child
->font
->scale_y
= font
->scale_y
;
7654 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7655 child
->font
->base_font
= font
;
7656 TRACE("created child font %p for base %p\n", child
->font
, font
);
7660 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
7663 CHILD_FONT
*child_font
;
7666 font
= font
->base_font
;
7668 *linked_font
= font
;
7670 if((*glyph
= get_glyph_index(font
, c
)))
7673 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7674 *vert
= (o
!= *glyph
);
7678 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
7680 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7682 if(!child_font
->font
)
7683 if(!load_child_font(font
, child_font
))
7686 if(!child_font
->font
->ft_face
)
7688 g
= get_glyph_index(child_font
->font
, c
);
7690 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7694 *linked_font
= child_font
->font
;
7705 /*************************************************************
7706 * freetype_GetCharWidth
7708 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7710 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7714 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7718 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7719 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7722 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7725 EnterCriticalSection( &freetype_cs
);
7726 for(c
= firstChar
; c
<= lastChar
; c
++) {
7727 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7728 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7730 LeaveCriticalSection( &freetype_cs
);
7734 /*************************************************************
7735 * freetype_GetCharABCWidths
7737 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7739 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7742 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7746 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7747 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7750 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7753 EnterCriticalSection( &freetype_cs
);
7755 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7756 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7758 LeaveCriticalSection( &freetype_cs
);
7762 /*************************************************************
7763 * freetype_GetCharABCWidthsI
7765 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7767 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7770 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7774 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7775 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7778 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7782 EnterCriticalSection( &freetype_cs
);
7784 for(c
= 0; c
< count
; c
++, buffer
++)
7785 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7786 &gm
, buffer
, 0, NULL
, &identity
);
7788 LeaveCriticalSection( &freetype_cs
);
7792 /*************************************************************
7793 * freetype_GetTextExtentExPoint
7795 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7797 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7801 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7805 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7806 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7809 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7812 EnterCriticalSection( &freetype_cs
);
7814 for (idx
= pos
= 0; idx
< count
; idx
++)
7816 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7817 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7821 LeaveCriticalSection( &freetype_cs
);
7825 /*************************************************************
7826 * freetype_GetTextExtentExPointI
7828 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7830 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7834 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7838 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7839 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7842 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7845 EnterCriticalSection( &freetype_cs
);
7847 for (idx
= pos
= 0; idx
< count
; idx
++)
7849 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7850 &gm
, &abc
, 0, NULL
, &identity
);
7851 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7855 LeaveCriticalSection( &freetype_cs
);
7859 /*************************************************************
7860 * freetype_GetFontData
7862 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7864 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7868 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7869 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7872 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7873 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7874 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7876 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7879 /*************************************************************
7880 * freetype_GetTextFace
7882 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7885 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7889 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7890 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7893 n
= strlenW(physdev
->font
->name
) + 1;
7896 lstrcpynW(str
, physdev
->font
->name
, count
);
7902 /*************************************************************
7903 * freetype_GetTextCharsetInfo
7905 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7907 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7911 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7912 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7914 if (fs
) *fs
= physdev
->font
->fs
;
7915 return physdev
->font
->charset
;
7918 /* Retrieve a list of supported Unicode ranges for a given font.
7919 * Can be called with NULL gs to calculate the buffer size. Returns
7920 * the number of ranges found.
7922 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7924 DWORD num_ranges
= 0;
7926 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7929 FT_ULong char_code
, char_code_prev
;
7932 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7934 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7935 face
->num_glyphs
, glyph_code
, char_code
);
7937 if (!glyph_code
) return 0;
7941 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7942 gs
->ranges
[0].cGlyphs
= 0;
7943 gs
->cGlyphsSupported
= 0;
7949 if (char_code
< char_code_prev
)
7951 ERR("expected increasing char code from FT_Get_Next_Char\n");
7954 if (char_code
- char_code_prev
> 1)
7959 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7960 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7961 gs
->cGlyphsSupported
++;
7966 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7967 gs
->cGlyphsSupported
++;
7969 char_code_prev
= char_code
;
7970 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7974 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7979 /*************************************************************
7980 * freetype_GetFontUnicodeRanges
7982 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7984 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7985 DWORD size
, num_ranges
;
7989 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7990 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7993 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7994 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7997 glyphset
->cbThis
= size
;
7998 glyphset
->cRanges
= num_ranges
;
7999 glyphset
->flAccel
= 0;
8004 /*************************************************************
8005 * freetype_FontIsLinked
8007 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
8009 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8014 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
8015 return dev
->funcs
->pFontIsLinked( dev
);
8019 EnterCriticalSection( &freetype_cs
);
8020 ret
= !list_empty(&physdev
->font
->child_fonts
);
8021 LeaveCriticalSection( &freetype_cs
);
8025 /*************************************************************************
8026 * GetRasterizerCaps (GDI32.@)
8028 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8030 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8031 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
8032 lprs
->nLanguageID
= 0;
8036 /*************************************************************
8037 * freetype_GdiRealizationInfo
8039 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
8041 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8042 realization_info_t
*info
= ptr
;
8046 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
8047 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
8050 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
8053 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8056 info
->cache_num
= physdev
->font
->cache_num
;
8057 info
->unknown2
= -1;
8061 /*************************************************************************
8062 * Kerning support for TrueType fonts
8064 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8066 struct TT_kern_table
8072 struct TT_kern_subtable
8081 USHORT horizontal
: 1;
8083 USHORT cross_stream
: 1;
8084 USHORT override
: 1;
8085 USHORT reserved1
: 4;
8091 struct TT_format0_kern_subtable
8095 USHORT entrySelector
;
8106 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8107 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8108 const USHORT
*glyph_to_char
,
8109 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8112 const struct TT_kern_pair
*tt_kern_pair
;
8114 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8116 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8118 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8119 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8120 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8122 if (!kern_pair
|| !cPairs
)
8125 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8127 nPairs
= min(nPairs
, cPairs
);
8129 for (i
= 0; i
< nPairs
; i
++)
8131 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8132 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8133 /* this algorithm appears to better match what Windows does */
8134 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8135 if (kern_pair
->iKernAmount
< 0)
8137 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8138 kern_pair
->iKernAmount
-= font
->ppem
;
8140 else if (kern_pair
->iKernAmount
> 0)
8142 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8143 kern_pair
->iKernAmount
+= font
->ppem
;
8145 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8147 TRACE("left %u right %u value %d\n",
8148 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8152 TRACE("copied %u entries\n", nPairs
);
8156 /*************************************************************
8157 * freetype_GetKerningPairs
8159 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8163 const struct TT_kern_table
*tt_kern_table
;
8164 const struct TT_kern_subtable
*tt_kern_subtable
;
8166 USHORT
*glyph_to_char
;
8168 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8170 if (!(font
= physdev
->font
))
8172 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8173 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8177 EnterCriticalSection( &freetype_cs
);
8178 if (font
->total_kern_pairs
!= (DWORD
)-1)
8180 if (cPairs
&& kern_pair
)
8182 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8183 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8185 else cPairs
= font
->total_kern_pairs
;
8187 LeaveCriticalSection( &freetype_cs
);
8191 font
->total_kern_pairs
= 0;
8193 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8195 if (length
== GDI_ERROR
)
8197 TRACE("no kerning data in the font\n");
8198 LeaveCriticalSection( &freetype_cs
);
8202 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8205 WARN("Out of memory\n");
8206 LeaveCriticalSection( &freetype_cs
);
8210 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8212 /* build a glyph index to char code map */
8213 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8216 WARN("Out of memory allocating a glyph index to char code map\n");
8217 HeapFree(GetProcessHeap(), 0, buf
);
8218 LeaveCriticalSection( &freetype_cs
);
8222 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8228 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8230 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8231 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8235 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8237 /* FIXME: This doesn't match what Windows does: it does some fancy
8238 * things with duplicate glyph index to char code mappings, while
8239 * we just avoid overriding existing entries.
8241 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8242 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8244 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8251 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8252 for (n
= 0; n
<= 65535; n
++)
8253 glyph_to_char
[n
] = (USHORT
)n
;
8256 tt_kern_table
= buf
;
8257 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8258 TRACE("version %u, nTables %u\n",
8259 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8261 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8263 for (i
= 0; i
< nTables
; i
++)
8265 struct TT_kern_subtable tt_kern_subtable_copy
;
8267 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8268 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8269 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8271 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8272 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8273 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8275 /* According to the TrueType specification this is the only format
8276 * that will be properly interpreted by Windows and OS/2
8278 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8280 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8282 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8283 glyph_to_char
, NULL
, 0);
8284 font
->total_kern_pairs
+= new_chunk
;
8286 if (!font
->kern_pairs
)
8287 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8288 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8290 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8291 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8293 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8294 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8297 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8299 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8302 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8303 HeapFree(GetProcessHeap(), 0, buf
);
8305 if (cPairs
&& kern_pair
)
8307 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8308 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8310 else cPairs
= font
->total_kern_pairs
;
8312 LeaveCriticalSection( &freetype_cs
);
8316 static const struct gdi_dc_funcs freetype_funcs
=
8318 NULL
, /* pAbortDoc */
8319 NULL
, /* pAbortPath */
8320 NULL
, /* pAlphaBlend */
8321 NULL
, /* pAngleArc */
8324 NULL
, /* pBeginPath */
8325 NULL
, /* pBlendImage */
8327 NULL
, /* pCloseFigure */
8328 NULL
, /* pCreateCompatibleDC */
8329 freetype_CreateDC
, /* pCreateDC */
8330 freetype_DeleteDC
, /* pDeleteDC */
8331 NULL
, /* pDeleteObject */
8332 NULL
, /* pDeviceCapabilities */
8333 NULL
, /* pEllipse */
8335 NULL
, /* pEndPage */
8336 NULL
, /* pEndPath */
8337 freetype_EnumFonts
, /* pEnumFonts */
8338 NULL
, /* pEnumICMProfiles */
8339 NULL
, /* pExcludeClipRect */
8340 NULL
, /* pExtDeviceMode */
8341 NULL
, /* pExtEscape */
8342 NULL
, /* pExtFloodFill */
8343 NULL
, /* pExtSelectClipRgn */
8344 NULL
, /* pExtTextOut */
8345 NULL
, /* pFillPath */
8346 NULL
, /* pFillRgn */
8347 NULL
, /* pFlattenPath */
8348 freetype_FontIsLinked
, /* pFontIsLinked */
8349 NULL
, /* pFrameRgn */
8350 NULL
, /* pGdiComment */
8351 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
8352 NULL
, /* pGetBoundsRect */
8353 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8354 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8355 freetype_GetCharWidth
, /* pGetCharWidth */
8356 NULL
, /* pGetDeviceCaps */
8357 NULL
, /* pGetDeviceGammaRamp */
8358 freetype_GetFontData
, /* pGetFontData */
8359 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8360 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8361 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8362 NULL
, /* pGetICMProfile */
8363 NULL
, /* pGetImage */
8364 freetype_GetKerningPairs
, /* pGetKerningPairs */
8365 NULL
, /* pGetNearestColor */
8366 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8367 NULL
, /* pGetPixel */
8368 NULL
, /* pGetSystemPaletteEntries */
8369 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8370 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8371 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8372 freetype_GetTextFace
, /* pGetTextFace */
8373 freetype_GetTextMetrics
, /* pGetTextMetrics */
8374 NULL
, /* pGradientFill */
8375 NULL
, /* pIntersectClipRect */
8376 NULL
, /* pInvertRgn */
8378 NULL
, /* pModifyWorldTransform */
8380 NULL
, /* pOffsetClipRgn */
8381 NULL
, /* pOffsetViewportOrg */
8382 NULL
, /* pOffsetWindowOrg */
8383 NULL
, /* pPaintRgn */
8386 NULL
, /* pPolyBezier */
8387 NULL
, /* pPolyBezierTo */
8388 NULL
, /* pPolyDraw */
8389 NULL
, /* pPolyPolygon */
8390 NULL
, /* pPolyPolyline */
8391 NULL
, /* pPolygon */
8392 NULL
, /* pPolyline */
8393 NULL
, /* pPolylineTo */
8394 NULL
, /* pPutImage */
8395 NULL
, /* pRealizeDefaultPalette */
8396 NULL
, /* pRealizePalette */
8397 NULL
, /* pRectangle */
8398 NULL
, /* pResetDC */
8399 NULL
, /* pRestoreDC */
8400 NULL
, /* pRoundRect */
8402 NULL
, /* pScaleViewportExt */
8403 NULL
, /* pScaleWindowExt */
8404 NULL
, /* pSelectBitmap */
8405 NULL
, /* pSelectBrush */
8406 NULL
, /* pSelectClipPath */
8407 freetype_SelectFont
, /* pSelectFont */
8408 NULL
, /* pSelectPalette */
8409 NULL
, /* pSelectPen */
8410 NULL
, /* pSetArcDirection */
8411 NULL
, /* pSetBkColor */
8412 NULL
, /* pSetBkMode */
8413 NULL
, /* pSetDCBrushColor */
8414 NULL
, /* pSetDCPenColor */
8415 NULL
, /* pSetDIBColorTable */
8416 NULL
, /* pSetDIBitsToDevice */
8417 NULL
, /* pSetDeviceClipping */
8418 NULL
, /* pSetDeviceGammaRamp */
8419 NULL
, /* pSetLayout */
8420 NULL
, /* pSetMapMode */
8421 NULL
, /* pSetMapperFlags */
8422 NULL
, /* pSetPixel */
8423 NULL
, /* pSetPolyFillMode */
8424 NULL
, /* pSetROP2 */
8425 NULL
, /* pSetRelAbs */
8426 NULL
, /* pSetStretchBltMode */
8427 NULL
, /* pSetTextAlign */
8428 NULL
, /* pSetTextCharacterExtra */
8429 NULL
, /* pSetTextColor */
8430 NULL
, /* pSetTextJustification */
8431 NULL
, /* pSetViewportExt */
8432 NULL
, /* pSetViewportOrg */
8433 NULL
, /* pSetWindowExt */
8434 NULL
, /* pSetWindowOrg */
8435 NULL
, /* pSetWorldTransform */
8436 NULL
, /* pStartDoc */
8437 NULL
, /* pStartPage */
8438 NULL
, /* pStretchBlt */
8439 NULL
, /* pStretchDIBits */
8440 NULL
, /* pStrokeAndFillPath */
8441 NULL
, /* pStrokePath */
8442 NULL
, /* pUnrealizePalette */
8443 NULL
, /* pWidenPath */
8444 NULL
, /* wine_get_wgl_driver */
8445 GDI_PRIORITY_FONT_DRV
/* priority */
8448 #else /* HAVE_FREETYPE */
8450 /*************************************************************************/
8452 BOOL
WineEngInit(void)
8457 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8459 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8463 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8465 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8469 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8471 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8475 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8476 LPCWSTR font_file
, LPCWSTR font_path
)
8482 /*************************************************************************
8483 * GetRasterizerCaps (GDI32.@)
8485 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8487 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8489 lprs
->nLanguageID
= 0;
8493 #endif /* HAVE_FREETYPE */