2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font
);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType
;
144 static FT_Library library
= 0;
151 static FT_Version_t FT_Version
;
152 static DWORD FT_SimpleVersion
;
154 static void *ft_handle
= NULL
;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face
);
158 MAKE_FUNCPTR(FT_Get_Char_Index
);
159 MAKE_FUNCPTR(FT_Get_First_Char
);
160 MAKE_FUNCPTR(FT_Get_Module
);
161 MAKE_FUNCPTR(FT_Get_Next_Char
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
166 MAKE_FUNCPTR(FT_Init_FreeType
);
167 MAKE_FUNCPTR(FT_Library_Version
);
168 MAKE_FUNCPTR(FT_Load_Glyph
);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
170 MAKE_FUNCPTR(FT_Matrix_Multiply
);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix
);
176 MAKE_FUNCPTR(FT_New_Face
);
177 MAKE_FUNCPTR(FT_New_Memory_Face
);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
179 MAKE_FUNCPTR(FT_Outline_Transform
);
180 MAKE_FUNCPTR(FT_Outline_Translate
);
181 MAKE_FUNCPTR(FT_Render_Glyph
);
182 MAKE_FUNCPTR(FT_Select_Charmap
);
183 MAKE_FUNCPTR(FT_Set_Charmap
);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
185 MAKE_FUNCPTR(FT_Vector_Transform
);
186 MAKE_FUNCPTR(FT_Vector_Unit
);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute
);
195 MAKE_FUNCPTR(FcFontList
);
196 MAKE_FUNCPTR(FcFontSetDestroy
);
197 MAKE_FUNCPTR(FcInit
);
198 MAKE_FUNCPTR(FcObjectSetAdd
);
199 MAKE_FUNCPTR(FcObjectSetCreate
);
200 MAKE_FUNCPTR(FcObjectSetDestroy
);
201 MAKE_FUNCPTR(FcPatternCreate
);
202 MAKE_FUNCPTR(FcPatternDestroy
);
203 MAKE_FUNCPTR(FcPatternGetBool
);
204 MAKE_FUNCPTR(FcPatternGetInteger
);
205 MAKE_FUNCPTR(FcPatternGetString
);
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
242 FT_Short internal_leading
;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
249 FT_Short height
, width
;
250 FT_Pos size
, x_ppem
, y_ppem
;
256 NEWTEXTMETRICEXW ntm
;
260 typedef struct tagFace
{
266 DWORD font_data_size
;
270 FT_Fixed font_version
;
273 Bitmap_Size size
; /* set if face is a bitmap */
274 BOOL external
; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily
*family
;
277 /* Cached data for Enum */
278 struct enum_data
*cached_enum_data
;
281 typedef struct tagFamily
{
286 struct list
*replacement
;
291 INT adv
; /* These three hold to widths of the unrotated chars */
309 typedef struct tagHFONTLIST
{
324 struct list hfontlist
;
325 OUTLINETEXTMETRICW
*potm
;
326 DWORD total_kern_pairs
;
327 KERNINGPAIR
*kern_pairs
;
328 struct list child_fonts
;
330 /* the following members can be accessed without locking, they are never modified after creation */
332 struct font_mapping
*mapping
;
348 UINT ntmCellHeight
, ntmAvgWidth
;
357 const WCHAR
*font_name
;
362 struct enum_charset_element
{
365 WCHAR name
[LF_FACESIZE
];
368 struct enum_charset_list
{
370 struct enum_charset_element element
[32];
373 #define GM_BLOCK_SIZE 128
374 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
376 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
377 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
378 #define UNUSED_CACHE_SIZE 10
379 static struct list child_font_list
= LIST_INIT(child_font_list
);
380 static struct list system_links
= LIST_INIT(system_links
);
382 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
384 static struct list font_list
= LIST_INIT(font_list
);
386 struct freetype_physdev
388 struct gdi_physdev dev
;
392 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
394 return (struct freetype_physdev
*)dev
;
397 static const struct gdi_dc_funcs freetype_funcs
;
399 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
400 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
401 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
403 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
404 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
410 'W','i','n','d','o','w','s',' ','N','T','\\',
411 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
412 'F','o','n','t','s','\0'};
414 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
415 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
416 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
417 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
419 static const WCHAR
* const SystemFontValues
[] = {
426 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
427 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
429 /* Interesting and well-known (frequently-assumed!) font names */
430 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
431 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 };
432 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
433 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
434 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
435 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
436 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
437 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
439 static const WCHAR arial
[] = {'A','r','i','a','l',0};
440 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
441 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};
442 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};
443 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
444 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
445 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
446 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
447 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
448 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
450 static const WCHAR
*default_serif_list
[] =
454 bitstream_vera_serif
,
458 static const WCHAR
*default_fixed_list
[] =
462 bitstream_vera_sans_mono
,
466 static const WCHAR
*default_sans_list
[] =
479 typedef struct tagFontSubst
{
485 /* Registry font cache key and value names */
486 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
487 'F','o','n','t','s',0};
488 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
489 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
490 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
491 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
492 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
493 static const WCHAR face_vertical_value
[] = {'V','e','r','t','i','c','a','l',0};
494 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
495 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
496 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
497 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
498 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
499 static const WCHAR face_aa_value
[] = {'A','n','t','i','a','l','i','a','s','i','n','g',0};
500 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
501 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
502 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
503 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
516 static struct list mappings_list
= LIST_INIT( mappings_list
);
518 static UINT default_aa_flags
;
520 static CRITICAL_SECTION freetype_cs
;
521 static CRITICAL_SECTION_DEBUG critsect_debug
=
524 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
525 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
527 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
529 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
531 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
532 static BOOL use_default_fallback
= FALSE
;
534 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
535 static BOOL
get_outline_text_metrics(GdiFont
*font
);
536 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
538 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
539 'W','i','n','d','o','w','s',' ','N','T','\\',
540 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
541 'S','y','s','t','e','m','L','i','n','k',0};
543 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
544 'F','o','n','t','L','i','n','k','\\',
545 'S','y','s','t','e','m','L','i','n','k',0};
547 /****************************************
548 * Notes on .fon files
550 * The fonts System, FixedSys and Terminal are special. There are typically multiple
551 * versions installed for different resolutions and codepages. Windows stores which one to use
552 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
554 * FIXEDFON.FON FixedSys
556 * OEMFONT.FON Terminal
557 * LogPixels Current dpi set by the display control panel applet
558 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
559 * also has a LogPixels value that appears to mirror this)
561 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
562 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
563 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
564 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
565 * so that makes sense.
567 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
568 * to be mapped into the registry on Windows 2000 at least).
571 * ega80woa.fon=ega80850.fon
572 * ega40woa.fon=ega40850.fon
573 * cga80woa.fon=cga80850.fon
574 * cga40woa.fon=cga40850.fon
577 /* These are all structures needed for the GSUB table */
579 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
580 #define TATEGAKI_LOWER_BOUND 0x02F1
596 GSUB_ScriptRecord ScriptRecord
[1];
602 } GSUB_LangSysRecord
;
607 GSUB_LangSysRecord LangSysRecord
[1];
611 WORD LookupOrder
; /* Reserved */
612 WORD ReqFeatureIndex
;
614 WORD FeatureIndex
[1];
620 } GSUB_FeatureRecord
;
624 GSUB_FeatureRecord FeatureRecord
[1];
628 WORD FeatureParams
; /* Reserved */
630 WORD LookupListIndex
[1];
649 } GSUB_CoverageFormat1
;
654 WORD StartCoverageIndex
;
660 GSUB_RangeRecord RangeRecord
[1];
661 } GSUB_CoverageFormat2
;
664 WORD SubstFormat
; /* = 1 */
667 } GSUB_SingleSubstFormat1
;
670 WORD SubstFormat
; /* = 2 */
674 }GSUB_SingleSubstFormat2
;
676 #ifdef HAVE_CARBON_CARBON_H
677 static char *find_cache_dir(void)
681 static char cached_path
[MAX_PATH
];
682 static const char *wine
= "/Wine", *fonts
= "/Fonts";
684 if(*cached_path
) return cached_path
;
686 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
689 WARN("can't create cached data folder\n");
692 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
695 WARN("can't create cached data path\n");
699 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
701 ERR("Could not create full path\n");
705 strcat(cached_path
, wine
);
707 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
709 WARN("Couldn't mkdir %s\n", cached_path
);
713 strcat(cached_path
, fonts
);
714 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
716 WARN("Couldn't mkdir %s\n", cached_path
);
723 /******************************************************************
726 * Extracts individual TrueType font files from a Mac suitcase font
727 * and saves them into the user's caches directory (see
729 * Returns a NULL terminated array of filenames.
731 * We do this because they are apps that try to read ttf files
732 * themselves and they don't like Mac suitcase files.
734 static char **expand_mac_font(const char *path
)
741 const char *filename
;
745 unsigned int size
, max_size
;
748 TRACE("path %s\n", path
);
750 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
753 WARN("failed to get ref\n");
757 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
760 TRACE("no data fork, so trying resource fork\n");
761 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
764 TRACE("unable to open resource fork\n");
771 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
774 CloseResFile(res_ref
);
778 out_dir
= find_cache_dir();
780 filename
= strrchr(path
, '/');
781 if(!filename
) filename
= path
;
784 /* output filename has the form out_dir/filename_%04x.ttf */
785 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
792 unsigned short *num_faces_ptr
, num_faces
, face
;
795 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
797 fond
= Get1IndResource(fond_res
, idx
);
799 TRACE("got fond resource %d\n", idx
);
802 fam_rec
= *(FamRec
**)fond
;
803 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
804 num_faces
= GET_BE_WORD(*num_faces_ptr
);
806 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
807 TRACE("num faces %04x\n", num_faces
);
808 for(face
= 0; face
< num_faces
; face
++, assoc
++)
811 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
812 unsigned short size
, font_id
;
815 size
= GET_BE_WORD(assoc
->fontSize
);
816 font_id
= GET_BE_WORD(assoc
->fontID
);
819 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
823 TRACE("trying to load sfnt id %04x\n", font_id
);
824 sfnt
= GetResource(sfnt_res
, font_id
);
827 TRACE("can't get sfnt resource %04x\n", font_id
);
831 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
836 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
838 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
839 if(fd
!= -1 || errno
== EEXIST
)
843 unsigned char *sfnt_data
;
846 sfnt_data
= *(unsigned char**)sfnt
;
847 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
851 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
854 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
856 ret
.array
[ret
.size
++] = output
;
860 WARN("unable to create %s\n", output
);
861 HeapFree(GetProcessHeap(), 0, output
);
864 ReleaseResource(sfnt
);
867 ReleaseResource(fond
);
870 CloseResFile(res_ref
);
875 #endif /* HAVE_CARBON_CARBON_H */
877 static inline BOOL
is_win9x(void)
879 return GetVersion() & 0x80000000;
882 This function builds an FT_Fixed from a double. It fails if the absolute
883 value of the float number is greater than 32768.
885 static inline FT_Fixed
FT_FixedFromFloat(double f
)
891 This function builds an FT_Fixed from a FIXED. It simply put f.value
892 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
894 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
896 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
899 static BOOL
is_hinting_enabled(void)
901 static int enabled
= -1;
905 /* Use the >= 2.2.0 function if available */
906 if (pFT_Get_TrueType_Engine_Type
)
908 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
909 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
911 #ifdef FT_DRIVER_HAS_HINTER
914 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
915 FT_Module mod
= pFT_Get_Module(library
, "truetype");
916 enabled
= (mod
&& FT_DRIVER_HAS_HINTER(mod
));
919 else enabled
= FALSE
;
920 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
925 static BOOL
is_subpixel_rendering_enabled( void )
927 #ifdef HAVE_FREETYPE_FTLCDFIL_H
928 static int enabled
= -1;
931 enabled
= (pFT_Library_SetLcdFilter
&&
932 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
933 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
942 static const struct list
*get_face_list_from_family(const Family
*family
)
944 if (!list_empty(&family
->faces
))
945 return &family
->faces
;
947 return family
->replacement
;
950 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
956 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
958 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
960 const struct list
*face_list
;
961 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
963 face_list
= get_face_list_from_family(family
);
964 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
968 file
= strrchrW(face
->file
, '/');
973 if(!strcmpiW(file
, file_name
)) return face
;
979 static Family
*find_family_from_name(const WCHAR
*name
)
983 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
985 if(!strcmpiW(family
->FamilyName
, name
))
992 static Family
*find_family_from_any_name(const WCHAR
*name
)
996 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
998 if(!strcmpiW(family
->FamilyName
, name
))
1000 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1007 static void DumpSubstList(void)
1011 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1013 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1014 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1015 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1017 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1018 debugstr_w(psub
->to
.name
));
1023 static LPWSTR
strdupW(LPCWSTR p
)
1026 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1027 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1028 memcpy(ret
, p
, len
);
1032 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1037 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1039 if(!strcmpiW(element
->from
.name
, from_name
) &&
1040 (element
->from
.charset
== from_charset
||
1041 element
->from
.charset
== -1))
1048 #define ADD_FONT_SUBST_FORCE 1
1050 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1052 FontSubst
*from_exist
, *to_exist
;
1054 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1056 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1058 list_remove(&from_exist
->entry
);
1059 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1060 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1061 HeapFree(GetProcessHeap(), 0, from_exist
);
1067 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1071 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1072 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1075 list_add_tail(subst_list
, &subst
->entry
);
1080 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1081 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1082 HeapFree(GetProcessHeap(), 0, subst
);
1086 static WCHAR
*towstr(UINT cp
, const char *str
)
1091 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1092 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1093 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1097 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1099 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1100 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1101 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1105 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1107 CHAR
*p
= strrchr(str
, ',');
1111 nc
->charset
= strtol(p
+1, NULL
, 10);
1114 nc
->name
= towstr(CP_ACP
, str
);
1117 static void LoadSubstList(void)
1121 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1125 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1126 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1127 &hkey
) == ERROR_SUCCESS
) {
1129 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1130 &valuelen
, &datalen
, NULL
, NULL
);
1132 valuelen
++; /* returned value doesn't include room for '\0' */
1133 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1134 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1138 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1139 &dlen
) == ERROR_SUCCESS
) {
1140 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1142 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1143 split_subst_info(&psub
->from
, value
);
1144 split_subst_info(&psub
->to
, data
);
1146 /* Win 2000 doesn't allow mapping between different charsets
1147 or mapping of DEFAULT_CHARSET */
1148 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1149 psub
->to
.charset
== DEFAULT_CHARSET
) {
1150 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1151 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1152 HeapFree(GetProcessHeap(), 0, psub
);
1154 add_font_subst(&font_subst_list
, psub
, 0);
1156 /* reset dlen and vlen */
1160 HeapFree(GetProcessHeap(), 0, data
);
1161 HeapFree(GetProcessHeap(), 0, value
);
1167 /*****************************************************************
1168 * get_name_table_entry
1170 * Supply the platform, encoding, language and name ids in req
1171 * and if the name exists the function will fill in the string
1172 * and string_len members. The string is owned by FreeType so
1173 * don't free it. Returns TRUE if the name is found else FALSE.
1175 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1178 FT_UInt num_names
, name_index
;
1180 if(FT_IS_SFNT(ft_face
))
1182 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1184 for(name_index
= 0; name_index
< num_names
; name_index
++)
1186 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1188 if((name
.platform_id
== req
->platform_id
) &&
1189 ((name
.encoding_id
== TT_MS_ID_UNICODE_CS
) || (name
.encoding_id
== TT_MS_ID_SYMBOL_CS
)) &&
1190 (name
.language_id
== req
->language_id
) &&
1191 (name
.name_id
== req
->name_id
))
1193 req
->string
= name
.string
;
1194 req
->string_len
= name
.string_len
;
1201 req
->string_len
= 0;
1205 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1210 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1211 name
.language_id
= language_id
;
1212 name
.name_id
= name_id
;
1214 if(get_name_table_entry(ft_face
, &name
))
1218 /* String is not nul terminated and string_len is a byte length. */
1219 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1220 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1222 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1223 ret
[i
] = GET_BE_WORD(*tmp
);
1226 TRACE("Got localised name %s\n", debugstr_w(ret
));
1232 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1234 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1235 if (f1
->scalable
) return TRUE
;
1236 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1237 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1240 static inline void free_face( Face
*face
)
1242 HeapFree( GetProcessHeap(), 0, face
->file
);
1243 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1244 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1245 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1246 HeapFree( GetProcessHeap(), 0, face
);
1249 static inline void free_family( Family
*family
)
1251 Face
*face
, *cursor2
;
1253 LIST_FOR_EACH_ENTRY_SAFE( face
, cursor2
, &family
->faces
, Face
, entry
)
1255 list_remove( &face
->entry
);
1258 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1259 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1260 HeapFree( GetProcessHeap(), 0, family
);
1263 static inline int style_order(const Face
*face
)
1265 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1273 case NTM_BOLD
| NTM_ITALIC
:
1276 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1277 debugstr_w(face
->family
->FamilyName
),
1278 debugstr_w(face
->StyleName
),
1284 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1288 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1290 if (faces_equal( face
, cursor
))
1292 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1293 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1294 cursor
->font_version
, face
->font_version
);
1296 if (face
->font_version
<= cursor
->font_version
)
1298 TRACE("Original font %s is newer so skipping %s\n",
1299 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1304 TRACE("Replacing original %s with %s\n",
1305 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1306 list_add_before( &cursor
->entry
, &face
->entry
);
1307 face
->family
= family
;
1308 list_remove( &cursor
->entry
);
1309 free_face( cursor
);
1314 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1316 if (style_order( face
) < style_order( cursor
)) break;
1319 list_add_before( &cursor
->entry
, &face
->entry
);
1320 face
->family
= family
;
1324 /****************************************************************
1325 * NB This function stores the ptrs to the strings to save copying.
1326 * Don't free them after calling.
1328 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1330 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1331 family
->FamilyName
= name
;
1332 family
->EnglishName
= english_name
;
1333 list_init( &family
->faces
);
1334 family
->replacement
= &family
->faces
;
1339 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1341 DWORD type
, size
= sizeof(DWORD
);
1343 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1344 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1347 return ERROR_BAD_CONFIGURATION
;
1349 return ERROR_SUCCESS
;
1352 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1354 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1357 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1359 DWORD needed
, strike_index
= 0;
1362 /* If we have a File Name key then this is a real font, not just the parent
1363 key of a bunch of non-scalable strikes */
1364 needed
= buffer_size
;
1365 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1368 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1369 face
->cached_enum_data
= NULL
;
1371 face
->file
= strdupW( buffer
);
1372 face
->StyleName
= strdupW(face_name
);
1374 needed
= buffer_size
;
1375 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1376 face
->FullName
= strdupW( buffer
);
1378 face
->FullName
= NULL
;
1380 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1381 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1382 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1383 reg_load_dword(hkey_face
, face_vertical_value
, (DWORD
*)&face
->vertical
);
1384 reg_load_dword(hkey_face
, face_aa_value
, (DWORD
*)&face
->aa_flags
);
1386 needed
= sizeof(face
->fs
);
1387 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1389 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1391 face
->scalable
= TRUE
;
1392 memset(&face
->size
, 0, sizeof(face
->size
));
1396 face
->scalable
= FALSE
;
1397 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1398 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1399 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1400 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1401 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1403 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1404 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1405 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1408 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1409 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1410 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1411 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1413 insert_face_in_family_list(face
, family
);
1415 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1418 /* load bitmap strikes */
1420 needed
= buffer_size
;
1421 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1423 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1425 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1426 RegCloseKey(hkey_strike
);
1428 needed
= buffer_size
;
1432 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1434 DWORD size
, family_index
= 0;
1439 size
= sizeof(buffer
);
1440 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1442 WCHAR
*english_family
= NULL
;
1443 WCHAR
*family_name
= strdupW( buffer
);
1444 DWORD face_index
= 0;
1446 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1447 TRACE("opened family key %s\n", debugstr_w(family_name
));
1448 size
= sizeof(buffer
);
1449 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1450 english_family
= strdupW( buffer
);
1452 family
= create_family(family_name
, english_family
);
1453 list_add_tail(&font_list
, &family
->entry
);
1457 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1458 subst
->from
.name
= strdupW(english_family
);
1459 subst
->from
.charset
= -1;
1460 subst
->to
.name
= strdupW(family_name
);
1461 subst
->to
.charset
= -1;
1462 add_font_subst(&font_subst_list
, subst
, 0);
1465 size
= sizeof(buffer
);
1466 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1468 WCHAR
*face_name
= strdupW( buffer
);
1471 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1473 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1474 RegCloseKey(hkey_face
);
1476 HeapFree( GetProcessHeap(), 0, face_name
);
1477 size
= sizeof(buffer
);
1479 RegCloseKey(hkey_family
);
1480 size
= sizeof(buffer
);
1484 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1487 HKEY hkey_wine_fonts
;
1489 /* We don't want to create the fonts key as volatile, so open this first */
1490 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1491 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1492 if(ret
!= ERROR_SUCCESS
)
1494 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1498 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1499 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1500 RegCloseKey(hkey_wine_fonts
);
1504 static void add_face_to_cache(Face
*face
)
1506 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1507 WCHAR
*face_key_name
;
1509 create_font_cache_key(&hkey_font_cache
, NULL
);
1511 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1512 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1513 if(face
->family
->EnglishName
)
1514 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1515 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1518 face_key_name
= face
->StyleName
;
1521 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1522 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1523 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1525 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1528 HeapFree(GetProcessHeap(), 0, face_key_name
);
1530 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1531 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1533 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1534 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1536 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1537 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1538 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1539 if (face
->vertical
) reg_save_dword(hkey_face
, face_vertical_value
, face
->vertical
);
1540 if (face
->aa_flags
) reg_save_dword(hkey_face
, face_aa_value
, face
->aa_flags
);
1542 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1546 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1547 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1548 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1549 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1550 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1551 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1553 RegCloseKey(hkey_face
);
1554 RegCloseKey(hkey_family
);
1555 RegCloseKey(hkey_font_cache
);
1558 static WCHAR
*prepend_at(WCHAR
*family
)
1565 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1567 strcpyW(str
+ 1, family
);
1568 HeapFree(GetProcessHeap(), 0, family
);
1572 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1574 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1575 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1577 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1583 else if (!strcmpiW( *name
, *english
))
1585 HeapFree( GetProcessHeap(), 0, *english
);
1591 *name
= prepend_at( *name
);
1592 *english
= prepend_at( *english
);
1596 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1599 WCHAR
*name
, *english_name
;
1601 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1603 family
= find_family_from_name( name
);
1607 family
= create_family( name
, english_name
);
1608 list_add_tail( &font_list
, &family
->entry
);
1612 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1613 subst
->from
.name
= strdupW( english_name
);
1614 subst
->from
.charset
= -1;
1615 subst
->to
.name
= strdupW( name
);
1616 subst
->to
.charset
= -1;
1617 add_font_subst( &font_subst_list
, subst
, 0 );
1622 HeapFree( GetProcessHeap(), 0, name
);
1623 HeapFree( GetProcessHeap(), 0, english_name
);
1629 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1631 FT_Fixed version
= 0;
1634 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1635 if (header
) version
= header
->Font_Revision
;
1640 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1643 FT_ULong table_size
= 0;
1645 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1646 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1647 if (flags
== 0) flags
= NTM_REGULAR
;
1649 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1650 flags
|= NTM_PS_OPENTYPE
;
1655 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1657 int internal_leading
= 0;
1658 FT_WinFNT_HeaderRec winfnt_header
;
1660 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1661 internal_leading
= winfnt_header
.internal_leading
;
1663 return internal_leading
;
1666 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1671 FT_WinFNT_HeaderRec winfnt_header
;
1674 memset( fs
, 0, sizeof(*fs
) );
1676 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1679 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1680 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1681 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1682 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1684 if (os2
->version
== 0)
1686 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1687 fs
->fsCsb
[0] = FS_LATIN1
;
1689 fs
->fsCsb
[0] = FS_SYMBOL
;
1693 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1694 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1699 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1701 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1702 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1703 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1708 if (fs
->fsCsb
[0] == 0)
1710 /* let's see if we can find any interesting cmaps */
1711 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1713 switch (ft_face
->charmaps
[i
]->encoding
)
1715 case FT_ENCODING_UNICODE
:
1716 case FT_ENCODING_APPLE_ROMAN
:
1717 fs
->fsCsb
[0] |= FS_LATIN1
;
1719 case FT_ENCODING_MS_SYMBOL
:
1720 fs
->fsCsb
[0] |= FS_SYMBOL
;
1729 #define ADDFONT_EXTERNAL_FONT 0x01
1730 #define ADDFONT_FORCE_BITMAP 0x02
1731 #define ADDFONT_ADD_TO_CACHE 0x04
1732 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
1734 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1735 DWORD flags
, BOOL vertical
, DWORD aa_flags
)
1737 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1738 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1740 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1741 if (!face
->StyleName
)
1742 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1743 if (!face
->StyleName
)
1745 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1748 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1749 if (!face
->FullName
)
1750 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1752 face
->FullName
= prepend_at( face
->FullName
);
1756 face
->file
= towstr( CP_UNIXCP
, file
);
1757 face
->font_data_ptr
= NULL
;
1758 face
->font_data_size
= 0;
1763 face
->font_data_ptr
= font_data_ptr
;
1764 face
->font_data_size
= font_data_size
;
1767 face
->face_index
= face_index
;
1768 get_fontsig( ft_face
, &face
->fs
);
1769 face
->ntmFlags
= get_ntm_flags( ft_face
);
1770 face
->font_version
= get_font_version( ft_face
);
1772 if (FT_IS_SCALABLE( ft_face
))
1774 memset( &face
->size
, 0, sizeof(face
->size
) );
1775 face
->scalable
= TRUE
;
1779 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1780 size
->height
, size
->width
, size
->size
>> 6,
1781 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1782 face
->size
.height
= size
->height
;
1783 face
->size
.width
= size
->width
;
1784 face
->size
.size
= size
->size
;
1785 face
->size
.x_ppem
= size
->x_ppem
;
1786 face
->size
.y_ppem
= size
->y_ppem
;
1787 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1788 face
->scalable
= FALSE
;
1791 face
->vertical
= vertical
;
1792 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) != 0;
1793 face
->aa_flags
= aa_flags
;
1794 face
->family
= NULL
;
1795 face
->cached_enum_data
= NULL
;
1797 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1798 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1799 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1800 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1805 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1806 FT_Long face_index
, DWORD flags
, BOOL vertical
, DWORD aa_flags
)
1811 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
, vertical
, aa_flags
);
1812 family
= get_family( ft_face
, vertical
);
1813 if (!insert_face_in_family_list( face
, family
))
1819 if (flags
& ADDFONT_ADD_TO_CACHE
)
1820 add_face_to_cache( face
);
1822 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1823 debugstr_w(face
->StyleName
));
1826 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1827 FT_Long face_index
, BOOL allow_bitmap
)
1835 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1836 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1840 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1841 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1846 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1850 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1851 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1853 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1857 if (!FT_IS_SFNT( ft_face
))
1859 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1861 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1867 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1868 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1869 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1871 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1872 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1876 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1877 we don't want to load these. */
1878 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1882 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1884 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1890 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1892 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1898 pFT_Done_Face( ft_face
);
1902 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1905 FT_Long face_index
= 0, num_faces
;
1907 DWORD aa_flags
= HIWORD( flags
);
1909 if (!aa_flags
) aa_flags
= default_aa_flags
;
1911 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1912 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1914 #ifdef HAVE_CARBON_CARBON_H
1917 char **mac_list
= expand_mac_font(file
);
1920 BOOL had_one
= FALSE
;
1922 for(cursor
= mac_list
; *cursor
; cursor
++)
1925 AddFontToList(*cursor
, NULL
, 0, flags
);
1926 HeapFree(GetProcessHeap(), 0, *cursor
);
1928 HeapFree(GetProcessHeap(), 0, mac_list
);
1933 #endif /* HAVE_CARBON_CARBON_H */
1936 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_FORCE_BITMAP
);
1937 if (!ft_face
) return 0;
1939 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1941 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1942 pFT_Done_Face(ft_face
);
1946 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
, aa_flags
);
1949 if (FT_HAS_VERTICAL(ft_face
))
1951 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
, aa_flags
);
1955 num_faces
= ft_face
->num_faces
;
1956 pFT_Done_Face(ft_face
);
1957 } while(num_faces
> ++face_index
);
1961 static void DumpFontList(void)
1965 struct list
*family_elem_ptr
, *face_elem_ptr
;
1967 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1968 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1969 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1970 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1971 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1972 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1974 TRACE(" %d", face
->size
.height
);
1981 /***********************************************************
1982 * The replacement list is a way to map an entire font
1983 * family onto another family. For example adding
1985 * [HKCU\Software\Wine\Fonts\Replacements]
1986 * "Wingdings"="Winedings"
1988 * would enumerate the Winedings font both as Winedings and
1989 * Wingdings. However if a real Wingdings font is present the
1990 * replacement does not take place.
1993 static void LoadReplaceList(void)
1996 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2000 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2001 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2003 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2004 &valuelen
, &datalen
, NULL
, NULL
);
2006 valuelen
++; /* returned value doesn't include room for '\0' */
2007 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2008 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2012 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2013 &dlen
) == ERROR_SUCCESS
) {
2014 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2015 /* "NewName"="Oldname" */
2016 if(!find_family_from_any_name(value
))
2018 Family
* const family
= find_family_from_any_name(data
);
2021 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2022 if (new_family
!= NULL
)
2024 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2025 new_family
->FamilyName
= strdupW(value
);
2026 new_family
->EnglishName
= NULL
;
2027 list_init(&new_family
->faces
);
2028 new_family
->replacement
= &family
->faces
;
2029 list_add_tail(&font_list
, &new_family
->entry
);
2034 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2039 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2041 /* reset dlen and vlen */
2045 HeapFree(GetProcessHeap(), 0, data
);
2046 HeapFree(GetProcessHeap(), 0, value
);
2051 static const WCHAR
*font_links_list
[] =
2053 Lucida_Sans_Unicode
,
2054 Microsoft_Sans_Serif
,
2058 static const struct font_links_defaults_list
2060 /* Keyed off substitution for "MS Shell Dlg" */
2061 const WCHAR
*shelldlg
;
2062 /* Maximum of four substitutes, plus terminating NULL pointer */
2063 const WCHAR
*substitutes
[5];
2064 } font_links_defaults_list
[] =
2066 /* Non East-Asian */
2067 { Tahoma
, /* FIXME unverified ordering */
2068 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2070 /* Below lists are courtesy of
2071 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2075 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2077 /* Chinese Simplified */
2079 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2083 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2085 /* Chinese Traditional */
2087 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2092 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2094 SYSTEM_LINKS
*font_link
;
2096 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2098 if(!strcmpiW(font_link
->font_name
, name
))
2105 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2116 SYSTEM_LINKS
*font_link
;
2118 psub
= get_font_subst(&font_subst_list
, name
, -1);
2119 /* Don't store fonts that are only substitutes for other fonts */
2122 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2126 font_link
= find_font_link(name
);
2127 if (font_link
== NULL
)
2129 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2130 font_link
->font_name
= strdupW(name
);
2131 list_init(&font_link
->links
);
2132 list_add_tail(&system_links
, &font_link
->entry
);
2135 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2136 for (i
= 0; values
[i
] != NULL
; i
++)
2138 const struct list
*face_list
;
2139 CHILD_FONT
*child_font
;
2142 if (!strcmpiW(name
,value
))
2144 psub
= get_font_subst(&font_subst_list
, value
, -1);
2146 value
= psub
->to
.name
;
2147 family
= find_family_from_name(value
);
2151 /* Use first extant filename for this Family */
2152 face_list
= get_face_list_from_family(family
);
2153 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2157 file
= strrchrW(face
->file
, '/');
2166 face
= find_face_from_filename(file
, value
);
2169 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2173 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2174 child_font
->face
= face
;
2175 child_font
->font
= NULL
;
2176 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2177 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2178 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2179 child_font
->face
->face_index
);
2180 list_add_tail(&font_link
->links
, &child_font
->entry
);
2182 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2188 /*************************************************************
2191 static BOOL
init_system_links(void)
2195 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2196 WCHAR
*value
, *data
;
2197 WCHAR
*entry
, *next
;
2198 SYSTEM_LINKS
*font_link
, *system_font_link
;
2199 CHILD_FONT
*child_font
;
2200 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2201 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2202 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2207 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2209 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2210 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2211 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2212 val_len
= max_val
+ 1;
2213 data_len
= max_data
;
2215 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2217 psub
= get_font_subst(&font_subst_list
, value
, -1);
2218 /* Don't store fonts that are only substitutes for other fonts */
2221 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2224 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2225 font_link
->font_name
= strdupW(value
);
2226 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2227 list_init(&font_link
->links
);
2228 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2231 CHILD_FONT
*child_font
;
2233 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2235 next
= entry
+ strlenW(entry
) + 1;
2237 face_name
= strchrW(entry
, ',');
2241 while(isspaceW(*face_name
))
2244 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2246 face_name
= psub
->to
.name
;
2248 face
= find_face_from_filename(entry
, face_name
);
2251 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2255 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2256 child_font
->face
= face
;
2257 child_font
->font
= NULL
;
2258 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2259 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2260 TRACE("Adding file %s index %ld\n",
2261 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2262 list_add_tail(&font_link
->links
, &child_font
->entry
);
2264 list_add_tail(&system_links
, &font_link
->entry
);
2266 val_len
= max_val
+ 1;
2267 data_len
= max_data
;
2270 HeapFree(GetProcessHeap(), 0, value
);
2271 HeapFree(GetProcessHeap(), 0, data
);
2276 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2278 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2282 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2284 const FontSubst
*psub2
;
2285 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2287 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2289 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2290 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2292 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2293 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2295 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2297 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2303 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2306 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2307 system_font_link
->font_name
= strdupW(System
);
2308 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2309 list_init(&system_font_link
->links
);
2311 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2314 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2315 child_font
->face
= face
;
2316 child_font
->font
= NULL
;
2317 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2318 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2319 TRACE("Found Tahoma in %s index %ld\n",
2320 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2321 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2323 font_link
= find_font_link(Tahoma
);
2324 if (font_link
!= NULL
)
2326 CHILD_FONT
*font_link_entry
;
2327 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2329 CHILD_FONT
*new_child
;
2330 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2331 new_child
->face
= font_link_entry
->face
;
2332 new_child
->font
= NULL
;
2333 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2334 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2335 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2338 list_add_tail(&system_links
, &system_font_link
->entry
);
2342 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2345 struct dirent
*dent
;
2346 char path
[MAX_PATH
];
2348 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2350 dir
= opendir(dirname
);
2352 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2355 while((dent
= readdir(dir
)) != NULL
) {
2356 struct stat statbuf
;
2358 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2361 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2363 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2365 if(stat(path
, &statbuf
) == -1)
2367 WARN("Can't stat %s\n", debugstr_a(path
));
2370 if(S_ISDIR(statbuf
.st_mode
))
2371 ReadFontDir(path
, external_fonts
);
2374 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2375 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2376 AddFontToList(path
, NULL
, 0, addfont_flags
);
2383 #ifdef SONAME_LIBFONTCONFIG
2385 static BOOL fontconfig_enabled
;
2387 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2393 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2394 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2396 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2400 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2401 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2402 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2403 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2404 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2410 static void init_fontconfig(void)
2412 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2416 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2420 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2421 LOAD_FUNCPTR(FcConfigSubstitute
);
2422 LOAD_FUNCPTR(FcFontList
);
2423 LOAD_FUNCPTR(FcFontSetDestroy
);
2424 LOAD_FUNCPTR(FcInit
);
2425 LOAD_FUNCPTR(FcObjectSetAdd
);
2426 LOAD_FUNCPTR(FcObjectSetCreate
);
2427 LOAD_FUNCPTR(FcObjectSetDestroy
);
2428 LOAD_FUNCPTR(FcPatternCreate
);
2429 LOAD_FUNCPTR(FcPatternDestroy
);
2430 LOAD_FUNCPTR(FcPatternGetBool
);
2431 LOAD_FUNCPTR(FcPatternGetInteger
);
2432 LOAD_FUNCPTR(FcPatternGetString
);
2437 FcPattern
*pattern
= pFcPatternCreate();
2438 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2439 default_aa_flags
= parse_aa_pattern( pattern
);
2440 pFcPatternDestroy( pattern
);
2441 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2442 fontconfig_enabled
= TRUE
;
2446 static void load_fontconfig_fonts(void)
2455 if (!fontconfig_enabled
) return;
2457 pat
= pFcPatternCreate();
2458 os
= pFcObjectSetCreate();
2459 pFcObjectSetAdd(os
, FC_FILE
);
2460 pFcObjectSetAdd(os
, FC_SCALABLE
);
2461 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2462 pFcObjectSetAdd(os
, FC_RGBA
);
2463 fontset
= pFcFontList(NULL
, pat
, os
);
2464 if(!fontset
) return;
2465 for(i
= 0; i
< fontset
->nfont
; i
++) {
2469 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2472 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2474 /* We're just interested in OT/TT fonts for now, so this hack just
2475 picks up the scalable fonts without extensions .pf[ab] to save time
2476 loading every other font */
2478 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2480 TRACE("not scalable\n");
2484 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2485 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2487 len
= strlen( file
);
2488 if(len
< 4) continue;
2489 ext
= &file
[ len
- 3 ];
2490 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2491 AddFontToList(file
, NULL
, 0,
2492 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2494 pFcFontSetDestroy(fontset
);
2495 pFcObjectSetDestroy(os
);
2496 pFcPatternDestroy(pat
);
2499 #elif defined(HAVE_CARBON_CARBON_H)
2501 static void load_mac_font_callback(const void *value
, void *context
)
2503 CFStringRef pathStr
= value
;
2507 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2508 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2509 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2511 TRACE("font file %s\n", path
);
2512 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2514 HeapFree(GetProcessHeap(), 0, path
);
2517 static void load_mac_fonts(void)
2519 CFStringRef removeDupesKey
;
2520 CFBooleanRef removeDupesValue
;
2521 CFDictionaryRef options
;
2522 CTFontCollectionRef col
;
2524 CFMutableSetRef paths
;
2527 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2528 removeDupesValue
= kCFBooleanTrue
;
2529 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2530 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2531 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2532 if (options
) CFRelease(options
);
2535 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2539 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2543 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2547 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2550 WARN("CFSetCreateMutable failed\n");
2555 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2557 CTFontDescriptorRef desc
;
2566 desc
= CFArrayGetValueAtIndex(descs
, i
);
2568 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2569 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2570 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2571 if (!font
) continue;
2573 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2580 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2582 if (status
!= noErr
) continue;
2584 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2587 ext
= CFURLCopyPathExtension(url
);
2590 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2591 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2600 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2602 if (!path
) continue;
2604 CFSetAddValue(paths
, path
);
2610 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2616 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2619 const char *data_dir
= wine_get_data_dir();
2621 if (!data_dir
) data_dir
= wine_get_build_dir();
2628 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2630 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2632 strcpy(unix_name
, data_dir
);
2633 strcat(unix_name
, "/fonts/");
2635 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2637 EnterCriticalSection( &freetype_cs
);
2638 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2639 LeaveCriticalSection( &freetype_cs
);
2640 HeapFree(GetProcessHeap(), 0, unix_name
);
2645 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2647 static const WCHAR slashW
[] = {'\\','\0'};
2649 WCHAR windowsdir
[MAX_PATH
];
2652 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2653 strcatW(windowsdir
, fontsW
);
2654 strcatW(windowsdir
, slashW
);
2655 strcatW(windowsdir
, file
);
2656 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2657 EnterCriticalSection( &freetype_cs
);
2658 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2659 LeaveCriticalSection( &freetype_cs
);
2660 HeapFree(GetProcessHeap(), 0, unixname
);
2665 static void load_system_fonts(void)
2668 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2669 const WCHAR
* const *value
;
2671 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2674 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2675 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2676 strcatW(windowsdir
, fontsW
);
2677 for(value
= SystemFontValues
; *value
; value
++) {
2678 dlen
= sizeof(data
);
2679 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2683 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2684 if((unixname
= wine_get_unix_file_name(pathW
))) {
2685 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2686 HeapFree(GetProcessHeap(), 0, unixname
);
2689 load_font_from_data_dir(data
);
2696 /*************************************************************
2698 * This adds registry entries for any externally loaded fonts
2699 * (fonts from fontconfig or FontDirs). It also deletes entries
2700 * of no longer existing fonts.
2703 static void update_reg_entries(void)
2705 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2710 struct list
*family_elem_ptr
, *face_elem_ptr
;
2712 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2714 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2715 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2716 ERR("Can't create Windows font reg key\n");
2720 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2721 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2722 ERR("Can't create Windows font reg key\n");
2726 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2727 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2728 ERR("Can't create external font reg key\n");
2732 /* enumerate the fonts and add external ones to the two keys */
2734 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2735 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2736 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2738 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2739 if(!face
->external
) continue;
2743 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2744 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2745 strcpyW(valueW
, face
->FullName
);
2749 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2750 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2751 strcpyW(valueW
, family
->FamilyName
);
2754 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
2755 path
= wine_get_dos_file_name( buffer
);
2756 HeapFree( GetProcessHeap(), 0, buffer
);
2760 else if ((file
= strrchrW(face
->file
, '/')))
2765 len
= strlenW(file
) + 1;
2766 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2767 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2768 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2770 HeapFree(GetProcessHeap(), 0, path
);
2771 HeapFree(GetProcessHeap(), 0, valueW
);
2775 if(external_key
) RegCloseKey(external_key
);
2776 if(win9x_key
) RegCloseKey(win9x_key
);
2777 if(winnt_key
) RegCloseKey(winnt_key
);
2781 static void delete_external_font_keys(void)
2783 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2784 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2788 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2789 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2790 ERR("Can't create Windows font reg key\n");
2794 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2795 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2796 ERR("Can't create Windows font reg key\n");
2800 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2801 ERR("Can't create external font reg key\n");
2805 /* Delete all external fonts added last time */
2807 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2808 &valuelen
, &datalen
, NULL
, NULL
);
2809 valuelen
++; /* returned value doesn't include room for '\0' */
2810 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2811 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2813 dlen
= datalen
* sizeof(WCHAR
);
2816 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2817 &dlen
) == ERROR_SUCCESS
) {
2819 RegDeleteValueW(winnt_key
, valueW
);
2820 RegDeleteValueW(win9x_key
, valueW
);
2821 /* reset dlen and vlen */
2825 HeapFree(GetProcessHeap(), 0, data
);
2826 HeapFree(GetProcessHeap(), 0, valueW
);
2828 /* Delete the old external fonts key */
2829 RegCloseKey(external_key
);
2830 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2833 if(win9x_key
) RegCloseKey(win9x_key
);
2834 if(winnt_key
) RegCloseKey(winnt_key
);
2837 /*************************************************************
2838 * WineEngAddFontResourceEx
2841 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2847 if (ft_handle
) /* do it only if we have freetype up and running */
2852 FIXME("Ignoring flags %x\n", flags
);
2854 if((unixname
= wine_get_unix_file_name(file
)))
2856 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2858 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2859 EnterCriticalSection( &freetype_cs
);
2860 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2861 LeaveCriticalSection( &freetype_cs
);
2862 HeapFree(GetProcessHeap(), 0, unixname
);
2864 if (!ret
&& !strchrW(file
, '\\')) {
2865 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2866 ret
= load_font_from_winfonts_dir(file
);
2868 /* Try in datadir/fonts (or builddir/fonts),
2869 * needed for Magic the Gathering Online
2871 ret
= load_font_from_data_dir(file
);
2878 /*************************************************************
2879 * WineEngAddFontMemResourceEx
2882 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2886 if (ft_handle
) /* do it only if we have freetype up and running */
2888 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2890 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2891 memcpy(pFontCopy
, pbFont
, cbFont
);
2893 EnterCriticalSection( &freetype_cs
);
2894 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2895 LeaveCriticalSection( &freetype_cs
);
2899 TRACE("AddFontToList failed\n");
2900 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2903 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2904 * For now return something unique but quite random
2906 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2907 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2914 /*************************************************************
2915 * WineEngRemoveFontResourceEx
2918 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2921 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2925 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
2931 if (!font_file
) return NULL
;
2933 file_len
= strlenW( font_file
);
2935 if (font_path
&& font_path
[0])
2937 int path_len
= strlenW( font_path
);
2938 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
2939 if (!fullname
) return NULL
;
2940 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
2941 fullname
[path_len
] = '\\';
2942 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
2946 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
2947 if (!len
) return NULL
;
2948 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2949 if (!fullname
) return NULL
;
2950 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
2953 unix_name
= wine_get_unix_file_name( fullname
);
2954 HeapFree( GetProcessHeap(), 0, fullname
);
2958 #include <pshpack1.h>
2961 WORD num_of_resources
;
2965 CHAR dfCopyright
[60];
2971 WORD dfInternalLeading
;
2972 WORD dfExternalLeading
;
2980 BYTE dfPitchAndFamily
;
2991 CHAR szFaceName
[LF_FACESIZE
];
2994 #include <poppack.h>
2996 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
2997 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
2999 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3001 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3004 WCHAR
*name
, *english_name
;
3006 NEWTEXTMETRICEXW ntm
;
3009 if (!ft_face
) return FALSE
;
3010 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0, FALSE
, 0 );
3011 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3012 family
= create_family( name
, english_name
);
3013 insert_face_in_family_list( face
, family
);
3014 pFT_Done_Face( ft_face
);
3016 GetEnumStructs( face
, &elf
, &ntm
, &type
);
3017 free_family( family
);
3019 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3021 memset( fd
, 0, sizeof(*fd
) );
3023 fd
->num_of_resources
= 1;
3025 fd
->dfVersion
= 0x200;
3026 fd
->dfSize
= sizeof(*fd
);
3027 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3028 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3029 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3031 fd
->dfHorizRes
= 72;
3032 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3033 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3034 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3035 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3036 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3037 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3038 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3039 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3041 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3042 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3043 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3044 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3045 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3046 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3047 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3048 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3049 fd
->dfWidthBytes
= 0;
3051 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3053 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3058 #define NE_FFLAGS_LIBMODULE 0x8000
3059 #define NE_OSFLAGS_WINDOWS 0x02
3061 static const char dos_string
[0x40] = "This is a TrueType resource file";
3062 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3064 #include <pshpack2.h>
3085 struct ne_typeinfo fontdir_type
;
3086 struct ne_nameinfo fontdir_name
;
3087 struct ne_typeinfo scalable_type
;
3088 struct ne_nameinfo scalable_name
;
3090 BYTE fontdir_res_name
[8];
3093 #include <poppack.h>
3095 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3099 DWORD size
, written
;
3101 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3102 char *font_fileA
, *last_part
, *ext
;
3103 IMAGE_DOS_HEADER dos
;
3104 IMAGE_OS2_HEADER ne
=
3106 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3108 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3109 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3111 struct rsrc_tab rsrc_tab
=
3115 { 0, 0, 0x0c50, 0x2c, 0 },
3117 { 0, 0, 0x0c50, 0x8001, 0 },
3119 { 7,'F','O','N','T','D','I','R'}
3122 memset( &dos
, 0, sizeof(dos
) );
3123 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3124 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3126 /* import name is last part\0, resident name is last part without extension
3127 non-resident name is "FONTRES:" + lfFaceName */
3129 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3130 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3131 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3133 last_part
= strrchr( font_fileA
, '\\' );
3134 if (last_part
) last_part
++;
3135 else last_part
= font_fileA
;
3136 import_name_len
= strlen( last_part
) + 1;
3138 ext
= strchr( last_part
, '.' );
3139 if (ext
) res_name_len
= ext
- last_part
;
3140 else res_name_len
= import_name_len
- 1;
3142 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3144 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3145 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3146 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3147 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3149 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3151 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3152 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3153 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3154 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3156 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3157 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3161 HeapFree( GetProcessHeap(), 0, font_fileA
);
3165 memcpy( ptr
, &dos
, sizeof(dos
) );
3166 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3167 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3169 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3170 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3172 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3173 *ptr
++ = res_name_len
;
3174 memcpy( ptr
, last_part
, res_name_len
);
3176 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3177 *ptr
++ = import_name_len
;
3178 memcpy( ptr
, last_part
, import_name_len
);
3180 ptr
= start
+ ne
.ne_nrestab
;
3181 *ptr
++ = non_res_name_len
;
3182 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3183 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3185 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3186 memcpy( ptr
, font_fileA
, font_file_len
);
3188 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3189 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3191 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3192 if (file
!= INVALID_HANDLE_VALUE
)
3194 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3196 CloseHandle( file
);
3199 HeapFree( GetProcessHeap(), 0, start
);
3200 HeapFree( GetProcessHeap(), 0, font_fileA
);
3205 /*************************************************************
3206 * WineEngCreateScalableFontResource
3209 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3210 LPCWSTR font_file
, LPCWSTR font_path
)
3212 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3213 struct fontdir fontdir
;
3216 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3217 SetLastError( ERROR_INVALID_PARAMETER
);
3220 if (hidden
) fontdir
.dfType
|= 0x80;
3221 ret
= create_fot( resource
, font_file
, &fontdir
);
3224 HeapFree( GetProcessHeap(), 0, unix_name
);
3228 static const struct nls_update_font_list
3230 UINT ansi_cp
, oem_cp
;
3231 const char *oem
, *fixed
, *system
;
3232 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3233 /* these are for font substitutes */
3234 const char *shelldlg
, *tmsrmn
;
3235 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3239 const char *from
, *to
;
3240 } arial_0
, courier_new_0
, times_new_roman_0
;
3241 } nls_update_font_list
[] =
3243 /* Latin 1 (United States) */
3244 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3245 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3246 "Tahoma","Times New Roman",
3247 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3250 /* Latin 1 (Multilingual) */
3251 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3252 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3253 "Tahoma","Times New Roman", /* FIXME unverified */
3254 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3257 /* Eastern Europe */
3258 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3259 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3260 "Tahoma","Times New Roman", /* FIXME unverified */
3261 "Fixedsys,238", "System,238",
3262 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3263 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3264 { "Arial CE,0", "Arial,238" },
3265 { "Courier New CE,0", "Courier New,238" },
3266 { "Times New Roman CE,0", "Times New Roman,238" }
3269 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3270 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3271 "Tahoma","Times New Roman", /* FIXME unverified */
3272 "Fixedsys,204", "System,204",
3273 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3274 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3275 { "Arial Cyr,0", "Arial,204" },
3276 { "Courier New Cyr,0", "Courier New,204" },
3277 { "Times New Roman Cyr,0", "Times New Roman,204" }
3280 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3281 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3282 "Tahoma","Times New Roman", /* FIXME unverified */
3283 "Fixedsys,161", "System,161",
3284 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3285 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3286 { "Arial Greek,0", "Arial,161" },
3287 { "Courier New Greek,0", "Courier New,161" },
3288 { "Times New Roman Greek,0", "Times New Roman,161" }
3291 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3292 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3293 "Tahoma","Times New Roman", /* FIXME unverified */
3294 "Fixedsys,162", "System,162",
3295 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3296 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3297 { "Arial Tur,0", "Arial,162" },
3298 { "Courier New Tur,0", "Courier New,162" },
3299 { "Times New Roman Tur,0", "Times New Roman,162" }
3302 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3303 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3304 "Tahoma","Times New Roman", /* FIXME unverified */
3305 "Fixedsys,177", "System,177",
3306 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3307 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3311 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3312 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3313 "Tahoma","Times New Roman", /* FIXME unverified */
3314 "Fixedsys,178", "System,178",
3315 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3316 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3320 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3321 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3322 "Tahoma","Times New Roman", /* FIXME unverified */
3323 "Fixedsys,186", "System,186",
3324 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3325 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3326 { "Arial Baltic,0", "Arial,186" },
3327 { "Courier New Baltic,0", "Courier New,186" },
3328 { "Times New Roman Baltic,0", "Times New Roman,186" }
3331 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3332 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3333 "Tahoma","Times New Roman", /* FIXME unverified */
3334 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3338 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3339 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3340 "Tahoma","Times New Roman", /* FIXME unverified */
3341 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3345 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3346 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3347 "MS UI Gothic","MS Serif",
3348 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3351 /* Chinese Simplified */
3352 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3353 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3354 "SimSun", "NSimSun",
3355 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3359 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3360 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3362 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3365 /* Chinese Traditional */
3366 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3367 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3368 "PMingLiU", "MingLiU",
3369 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3374 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3376 return ( ansi_cp
== 932 /* CP932 for Japanese */
3377 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3378 || ansi_cp
== 949 /* CP949 for Korean */
3379 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3382 static inline HKEY
create_fonts_NT_registry_key(void)
3386 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3387 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3391 static inline HKEY
create_fonts_9x_registry_key(void)
3395 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3396 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3400 static inline HKEY
create_config_fonts_registry_key(void)
3404 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3405 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3409 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3411 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3413 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3414 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3415 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3416 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3419 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3422 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3424 RegDeleteValueA(hkey
, name
);
3427 static void update_font_info(void)
3429 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3430 char buf
[40], cpbuf
[40];
3433 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3434 DWORD screen_dpi
= 96, font_dpi
= 0;
3437 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3438 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3439 &hkey
) == ERROR_SUCCESS
)
3441 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3445 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3448 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3450 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3451 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3452 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3453 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3454 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3456 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3457 if (is_dbcs_ansi_cp(ansi_cp
))
3458 use_default_fallback
= TRUE
;
3461 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3463 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3468 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3469 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3471 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3472 ansi_cp
, oem_cp
, screen_dpi
);
3474 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3475 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3478 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3482 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3483 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3485 hkey
= create_config_fonts_registry_key();
3486 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3487 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3488 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3491 hkey
= create_fonts_NT_registry_key();
3492 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3495 hkey
= create_fonts_9x_registry_key();
3496 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3499 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3501 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3502 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3503 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3504 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3506 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3507 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3508 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3509 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3510 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3511 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3512 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3513 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3515 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3516 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3517 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3525 /* Delete the FontSubstitutes from other locales */
3526 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3528 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3529 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3530 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3536 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3539 static BOOL
init_freetype(void)
3541 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3544 "Wine cannot find the FreeType font library. To enable Wine to\n"
3545 "use TrueType fonts please install a version of FreeType greater than\n"
3546 "or equal to 2.0.5.\n"
3547 "http://www.freetype.org\n");
3551 #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;}
3553 LOAD_FUNCPTR(FT_Done_Face
)
3554 LOAD_FUNCPTR(FT_Get_Char_Index
)
3555 LOAD_FUNCPTR(FT_Get_First_Char
)
3556 LOAD_FUNCPTR(FT_Get_Module
)
3557 LOAD_FUNCPTR(FT_Get_Next_Char
)
3558 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3559 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3560 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3561 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3562 LOAD_FUNCPTR(FT_Init_FreeType
)
3563 LOAD_FUNCPTR(FT_Library_Version
)
3564 LOAD_FUNCPTR(FT_Load_Glyph
)
3565 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3566 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3567 #ifndef FT_MULFIX_INLINED
3568 LOAD_FUNCPTR(FT_MulFix
)
3570 LOAD_FUNCPTR(FT_New_Face
)
3571 LOAD_FUNCPTR(FT_New_Memory_Face
)
3572 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3573 LOAD_FUNCPTR(FT_Outline_Transform
)
3574 LOAD_FUNCPTR(FT_Outline_Translate
)
3575 LOAD_FUNCPTR(FT_Render_Glyph
)
3576 LOAD_FUNCPTR(FT_Select_Charmap
)
3577 LOAD_FUNCPTR(FT_Set_Charmap
)
3578 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3579 LOAD_FUNCPTR(FT_Vector_Transform
)
3580 LOAD_FUNCPTR(FT_Vector_Unit
)
3582 /* Don't warn if these ones are missing */
3583 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3584 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3585 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3588 if(pFT_Init_FreeType(&library
) != 0) {
3589 ERR("Can't init FreeType library\n");
3590 wine_dlclose(ft_handle
, NULL
, 0);
3594 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3596 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3597 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3598 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3599 ((FT_Version
.patch
) & 0x0000ff);
3601 font_driver
= &freetype_funcs
;
3606 "Wine cannot find certain functions that it needs inside the FreeType\n"
3607 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3608 "FreeType to at least version 2.1.4.\n"
3609 "http://www.freetype.org\n");
3610 wine_dlclose(ft_handle
, NULL
, 0);
3615 static void init_font_list(void)
3617 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3618 static const WCHAR pathW
[] = {'P','a','t','h',0};
3620 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3621 WCHAR windowsdir
[MAX_PATH
];
3623 const char *data_dir
;
3625 #ifdef SONAME_LIBFONTCONFIG
3629 delete_external_font_keys();
3631 /* load the system bitmap fonts */
3632 load_system_fonts();
3634 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3635 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3636 strcatW(windowsdir
, fontsW
);
3637 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3639 ReadFontDir(unixname
, FALSE
);
3640 HeapFree(GetProcessHeap(), 0, unixname
);
3643 /* load the system truetype fonts */
3644 data_dir
= wine_get_data_dir();
3645 if (!data_dir
) data_dir
= wine_get_build_dir();
3646 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3648 strcpy(unixname
, data_dir
);
3649 strcat(unixname
, "/fonts/");
3650 ReadFontDir(unixname
, TRUE
);
3651 HeapFree(GetProcessHeap(), 0, unixname
);
3654 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3655 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3656 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3658 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3659 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3660 &hkey
) == ERROR_SUCCESS
)
3662 LPWSTR data
, valueW
;
3663 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3664 &valuelen
, &datalen
, NULL
, NULL
);
3666 valuelen
++; /* returned value doesn't include room for '\0' */
3667 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3668 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3671 dlen
= datalen
* sizeof(WCHAR
);
3673 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3674 &dlen
) == ERROR_SUCCESS
)
3676 if(data
[0] && (data
[1] == ':'))
3678 if((unixname
= wine_get_unix_file_name(data
)))
3680 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3681 HeapFree(GetProcessHeap(), 0, unixname
);
3684 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3686 WCHAR pathW
[MAX_PATH
];
3687 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3690 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3691 if((unixname
= wine_get_unix_file_name(pathW
)))
3693 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3694 HeapFree(GetProcessHeap(), 0, unixname
);
3697 load_font_from_data_dir(data
);
3699 /* reset dlen and vlen */
3704 HeapFree(GetProcessHeap(), 0, data
);
3705 HeapFree(GetProcessHeap(), 0, valueW
);
3709 #ifdef SONAME_LIBFONTCONFIG
3710 load_fontconfig_fonts();
3711 #elif defined(HAVE_CARBON_CARBON_H)
3715 /* then look in any directories that we've specified in the config file */
3716 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3717 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3723 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3725 len
+= sizeof(WCHAR
);
3726 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3727 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3729 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3730 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3731 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3732 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3737 LPSTR next
= strchr( ptr
, ':' );
3738 if (next
) *next
++ = 0;
3739 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3740 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3742 strcpy( unixname
, home
);
3743 strcat( unixname
, ptr
+ 1 );
3744 ReadFontDir( unixname
, TRUE
);
3745 HeapFree( GetProcessHeap(), 0, unixname
);
3748 ReadFontDir( ptr
, TRUE
);
3751 HeapFree( GetProcessHeap(), 0, valueA
);
3753 HeapFree( GetProcessHeap(), 0, valueW
);
3759 static BOOL
move_to_front(const WCHAR
*name
)
3761 Family
*family
, *cursor2
;
3762 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3764 if(!strcmpiW(family
->FamilyName
, name
))
3766 list_remove(&family
->entry
);
3767 list_add_head(&font_list
, &family
->entry
);
3774 static BOOL
set_default(const WCHAR
**name_list
)
3778 if (move_to_front(*name_list
)) return TRUE
;
3785 static void reorder_font_list(void)
3787 set_default( default_serif_list
);
3788 set_default( default_fixed_list
);
3789 set_default( default_sans_list
);
3792 /*************************************************************
3795 * Initialize FreeType library and create a list of available faces
3797 BOOL
WineEngInit(void)
3799 HKEY hkey_font_cache
;
3803 /* update locale dependent font info in registry */
3806 if(!init_freetype()) return FALSE
;
3808 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3810 ERR("Failed to create font mutex\n");
3813 WaitForSingleObject(font_mutex
, INFINITE
);
3815 create_font_cache_key(&hkey_font_cache
, &disposition
);
3817 if(disposition
== REG_CREATED_NEW_KEY
)
3820 load_font_list_from_cache(hkey_font_cache
);
3822 RegCloseKey(hkey_font_cache
);
3824 reorder_font_list();
3831 if(disposition
== REG_CREATED_NEW_KEY
)
3832 update_reg_entries();
3834 init_system_links();
3836 ReleaseMutex(font_mutex
);
3841 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3844 TT_HoriHeader
*pHori
;
3848 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3849 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3851 if(height
== 0) height
= 16;
3853 /* Calc. height of EM square:
3855 * For +ve lfHeight we have
3856 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3857 * Re-arranging gives:
3858 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3860 * For -ve lfHeight we have
3862 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3863 * with il = winAscent + winDescent - units_per_em]
3868 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3869 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3870 pHori
->Ascender
- pHori
->Descender
);
3872 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3873 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3881 static struct font_mapping
*map_font_file( const char *name
)
3883 struct font_mapping
*mapping
;
3887 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3888 if (fstat( fd
, &st
) == -1) goto error
;
3890 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3892 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3894 mapping
->refcount
++;
3899 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3902 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3905 if (mapping
->data
== MAP_FAILED
)
3907 HeapFree( GetProcessHeap(), 0, mapping
);
3910 mapping
->refcount
= 1;
3911 mapping
->dev
= st
.st_dev
;
3912 mapping
->ino
= st
.st_ino
;
3913 mapping
->size
= st
.st_size
;
3914 list_add_tail( &mappings_list
, &mapping
->entry
);
3922 static void unmap_font_file( struct font_mapping
*mapping
)
3924 if (!--mapping
->refcount
)
3926 list_remove( &mapping
->entry
);
3927 munmap( mapping
->data
, mapping
->size
);
3928 HeapFree( GetProcessHeap(), 0, mapping
);
3932 static LONG
load_VDMX(GdiFont
*, LONG
);
3934 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3941 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3945 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
3946 font
->mapping
= map_font_file( filename
);
3947 HeapFree( GetProcessHeap(), 0, filename
);
3950 WARN("failed to map %s\n", debugstr_w(face
->file
));
3953 data_ptr
= font
->mapping
->data
;
3954 data_size
= font
->mapping
->size
;
3958 data_ptr
= face
->font_data_ptr
;
3959 data_size
= face
->font_data_size
;
3962 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3964 ERR("FT_New_Face rets %d\n", err
);
3968 /* set it here, as load_VDMX needs it */
3969 font
->ft_face
= ft_face
;
3971 if(FT_IS_SCALABLE(ft_face
)) {
3972 /* load the VDMX table if we have one */
3973 font
->ppem
= load_VDMX(font
, height
);
3975 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3976 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3978 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3979 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3981 font
->ppem
= height
;
3982 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3983 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3989 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3991 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3992 a single face with the requested charset. The idea is to check if
3993 the selected font supports the current ANSI codepage, if it does
3994 return the corresponding charset, else return the first charset */
3997 int acp
= GetACP(), i
;
4001 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4003 const SYSTEM_LINKS
*font_link
;
4005 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4006 return csi
.ciCharset
;
4008 font_link
= find_font_link(family_name
);
4009 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4010 return csi
.ciCharset
;
4013 for(i
= 0; i
< 32; i
++) {
4015 if(face
->fs
.fsCsb
[0] & fs0
) {
4016 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4018 return csi
.ciCharset
;
4021 FIXME("TCI failing on %x\n", fs0
);
4025 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4026 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4028 return DEFAULT_CHARSET
;
4031 static GdiFont
*alloc_font(void)
4033 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4035 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4036 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4038 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4039 ret
->total_kern_pairs
= (DWORD
)-1;
4040 ret
->kern_pairs
= NULL
;
4041 list_init(&ret
->hfontlist
);
4042 list_init(&ret
->child_fonts
);
4046 static void free_font(GdiFont
*font
)
4048 struct list
*cursor
, *cursor2
;
4051 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
4053 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
4054 list_remove(cursor
);
4056 free_font(child
->font
);
4057 HeapFree(GetProcessHeap(), 0, child
);
4060 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
4062 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
4063 DeleteObject(hfontlist
->hfont
);
4064 list_remove(&hfontlist
->entry
);
4065 HeapFree(GetProcessHeap(), 0, hfontlist
);
4068 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4069 if (font
->mapping
) unmap_font_file( font
->mapping
);
4070 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4071 HeapFree(GetProcessHeap(), 0, font
->potm
);
4072 HeapFree(GetProcessHeap(), 0, font
->name
);
4073 for (i
= 0; i
< font
->gmsize
; i
++)
4074 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4075 HeapFree(GetProcessHeap(), 0, font
->gm
);
4076 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4077 HeapFree(GetProcessHeap(), 0, font
);
4081 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4083 FT_Face ft_face
= font
->ft_face
;
4087 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4094 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4096 /* make sure value of len is the value freetype says it needs */
4099 FT_ULong needed
= 0;
4100 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4101 if( !err
&& needed
< len
) len
= needed
;
4103 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4106 TRACE("Can't find table %c%c%c%c\n",
4107 /* bytes were reversed */
4108 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4109 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4115 /*************************************************************
4118 * load the vdmx entry for the specified height
4121 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4122 ( ( (FT_ULong)_x4 << 24 ) | \
4123 ( (FT_ULong)_x3 << 16 ) | \
4124 ( (FT_ULong)_x2 << 8 ) | \
4127 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4142 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4146 BYTE devXRatio
, devYRatio
;
4147 USHORT numRecs
, numRatios
;
4148 DWORD result
, offset
= -1;
4152 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4154 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4157 /* FIXME: need the real device aspect ratio */
4161 numRecs
= GET_BE_WORD(hdr
[1]);
4162 numRatios
= GET_BE_WORD(hdr
[2]);
4164 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4165 for(i
= 0; i
< numRatios
; i
++) {
4168 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4169 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4172 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4174 if((ratio
.xRatio
== 0 &&
4175 ratio
.yStartRatio
== 0 &&
4176 ratio
.yEndRatio
== 0) ||
4177 (devXRatio
== ratio
.xRatio
&&
4178 devYRatio
>= ratio
.yStartRatio
&&
4179 devYRatio
<= ratio
.yEndRatio
))
4181 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4182 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4183 offset
= GET_BE_WORD(tmp
);
4189 FIXME("No suitable ratio found\n");
4193 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4195 BYTE startsz
, endsz
;
4198 recs
= GET_BE_WORD(group
.recs
);
4199 startsz
= group
.startsz
;
4200 endsz
= group
.endsz
;
4202 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4204 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4205 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4206 if(result
== GDI_ERROR
) {
4207 FIXME("Failed to retrieve vTable\n");
4212 for(i
= 0; i
< recs
; i
++) {
4213 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4214 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4215 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4217 if(yMax
+ -yMin
== height
) {
4220 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4223 if(yMax
+ -yMin
> height
) {
4226 goto end
; /* failed */
4228 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4229 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4230 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4231 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4237 TRACE("ppem not found for height %d\n", height
);
4241 HeapFree(GetProcessHeap(), 0, vTable
);
4247 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4249 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4250 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4251 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4252 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4253 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4256 static void calc_hash(FONT_DESC
*pfd
)
4258 DWORD hash
= 0, *ptr
, two_chars
;
4262 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4264 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4266 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4268 pwc
= (WCHAR
*)&two_chars
;
4270 *pwc
= toupperW(*pwc
);
4272 *pwc
= toupperW(*pwc
);
4276 hash
^= !pfd
->can_use_bitmap
;
4281 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4286 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4290 fd
.can_use_bitmap
= can_use_bitmap
;
4293 /* try the child list */
4294 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
4295 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4296 if(!fontcmp(ret
, &fd
)) {
4297 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4298 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
4299 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4300 if(hflist
->hfont
== hfont
)
4306 /* try the in-use list */
4307 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
4308 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4309 if(!fontcmp(ret
, &fd
)) {
4310 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4311 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
4312 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4313 if(hflist
->hfont
== hfont
)
4316 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4317 hflist
->hfont
= hfont
;
4318 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4323 /* then the unused list */
4324 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4325 while(font_elem_ptr
) {
4326 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4327 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4328 if(!fontcmp(ret
, &fd
)) {
4329 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4330 assert(list_empty(&ret
->hfontlist
));
4331 TRACE("Found %p in unused list\n", ret
);
4332 list_remove(&ret
->entry
);
4333 list_add_head(&gdi_font_list
, &ret
->entry
);
4334 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4335 hflist
->hfont
= hfont
;
4336 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4343 static void add_to_cache(GdiFont
*font
)
4345 static DWORD cache_num
= 1;
4347 font
->cache_num
= cache_num
++;
4348 list_add_head(&gdi_font_list
, &font
->entry
);
4351 /*************************************************************
4352 * create_child_font_list
4354 static BOOL
create_child_font_list(GdiFont
*font
)
4357 SYSTEM_LINKS
*font_link
;
4358 CHILD_FONT
*font_link_entry
, *new_child
;
4362 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4363 font_name
= psub
? psub
->to
.name
: font
->name
;
4364 font_link
= find_font_link(font_name
);
4365 if (font_link
!= NULL
)
4367 TRACE("found entry in system list\n");
4368 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4370 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4371 new_child
->face
= font_link_entry
->face
;
4372 new_child
->font
= NULL
;
4373 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4374 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4379 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4380 * Sans Serif. This is how asian windows get default fallbacks for fonts
4382 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4383 font
->charset
!= OEM_CHARSET
&&
4384 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4386 font_link
= find_font_link(szDefaultFallbackLink
);
4387 if (font_link
!= NULL
)
4389 TRACE("found entry in default fallback list\n");
4390 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4392 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4393 new_child
->face
= font_link_entry
->face
;
4394 new_child
->font
= NULL
;
4395 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4396 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4405 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4407 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4409 if (pFT_Set_Charmap
)
4412 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4414 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4416 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4418 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4420 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4421 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4423 switch (ft_face
->charmaps
[i
]->platform_id
)
4426 cmap_def
= ft_face
->charmaps
[i
];
4428 case 0: /* Apple Unicode */
4429 cmap0
= ft_face
->charmaps
[i
];
4431 case 1: /* Macintosh */
4432 cmap1
= ft_face
->charmaps
[i
];
4435 cmap2
= ft_face
->charmaps
[i
];
4437 case 3: /* Microsoft */
4438 cmap3
= ft_face
->charmaps
[i
];
4443 if (cmap3
) /* prefer Microsoft cmap table */
4444 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4446 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4448 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4450 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4452 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4454 return ft_err
== FT_Err_Ok
;
4457 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4461 /*************************************************************
4464 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4465 LPCWSTR output
, const DEVMODEW
*devmode
)
4467 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4469 if (!physdev
) return FALSE
;
4470 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4475 /*************************************************************
4478 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4480 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4481 HeapFree( GetProcessHeap(), 0, physdev
);
4485 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4487 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4488 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4489 const FT_Encoding
*encs
= regular_order
;
4491 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4495 if (select_charmap( face
, *encs
)) break;
4501 #define GASP_GRIDFIT 0x01
4502 #define GASP_DOGRAY 0x02
4503 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4505 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4508 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4509 WORD
*alloced
= NULL
, *ptr
= buf
;
4510 WORD num_recs
, version
;
4514 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4515 if (size
== GDI_ERROR
) return FALSE
;
4516 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4517 if (size
> sizeof(buf
))
4519 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4520 if (!ptr
) return FALSE
;
4523 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4525 version
= GET_BE_WORD( *ptr
++ );
4526 num_recs
= GET_BE_WORD( *ptr
++ );
4528 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4530 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4536 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4537 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4540 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4544 HeapFree( GetProcessHeap(), 0, alloced
);
4548 /*************************************************************
4549 * freetype_SelectFont
4551 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4553 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4555 Face
*face
, *best
, *best_bitmap
;
4556 Family
*family
, *last_resort_family
;
4557 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4558 INT height
, width
= 0;
4559 unsigned int score
= 0, new_score
;
4560 signed int diff
= 0, newdiff
;
4561 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4566 FontSubst
*psub
= NULL
;
4567 DC
*dc
= get_dc_ptr( dev
->hdc
);
4568 const SYSTEM_LINKS
*font_link
;
4570 if (!hfont
) /* notification that the font has been changed by another driver */
4573 physdev
->font
= NULL
;
4574 release_dc_ptr( dc
);
4578 GetObjectW( hfont
, sizeof(lf
), &lf
);
4579 lf
.lfWidth
= abs(lf
.lfWidth
);
4581 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4583 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4584 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4585 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4588 if(dc
->GraphicsMode
== GM_ADVANCED
)
4590 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4591 /* Try to avoid not necessary glyph transformations */
4592 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4594 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4595 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4596 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4601 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4602 font scaling abilities. */
4603 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4604 dcmat
.eM21
= dcmat
.eM12
= 0;
4605 if (dc
->vport2WorldValid
)
4607 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4608 lf
.lfOrientation
= -lf
.lfOrientation
;
4609 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4610 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4614 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4615 dcmat
.eM21
, dcmat
.eM22
);
4618 EnterCriticalSection( &freetype_cs
);
4620 /* check the cache first */
4621 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4622 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4626 if(list_empty(&font_list
)) /* No fonts installed */
4628 TRACE("No fonts installed\n");
4632 TRACE("not in cache\n");
4635 ret
->font_desc
.matrix
= dcmat
;
4636 ret
->font_desc
.lf
= lf
;
4637 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4638 calc_hash(&ret
->font_desc
);
4639 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4640 hflist
->hfont
= hfont
;
4641 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4643 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4644 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4645 original value lfCharSet. Note this is a special case for
4646 Symbol and doesn't happen at least for "Wingdings*" */
4648 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4649 lf
.lfCharSet
= SYMBOL_CHARSET
;
4651 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4652 switch(lf
.lfCharSet
) {
4653 case DEFAULT_CHARSET
:
4654 csi
.fs
.fsCsb
[0] = 0;
4657 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4658 csi
.fs
.fsCsb
[0] = 0;
4664 if(lf
.lfFaceName
[0] != '\0') {
4665 CHILD_FONT
*font_link_entry
;
4666 LPWSTR FaceName
= lf
.lfFaceName
;
4668 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4671 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4672 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4673 if (psub
->to
.charset
!= -1)
4674 lf
.lfCharSet
= psub
->to
.charset
;
4677 /* We want a match on name and charset or just name if
4678 charset was DEFAULT_CHARSET. If the latter then
4679 we fixup the returned charset later in get_nearest_charset
4680 where we'll either use the charset of the current ansi codepage
4681 or if that's unavailable the first charset that the font supports.
4683 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4684 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4685 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4686 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4688 font_link
= find_font_link(family
->FamilyName
);
4689 face_list
= get_face_list_from_family(family
);
4690 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4691 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4692 if (!(face
->scalable
|| can_use_bitmap
))
4694 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4696 if (font_link
!= NULL
&&
4697 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4699 if (!csi
.fs
.fsCsb
[0])
4705 /* Search by full face name. */
4706 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4707 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4708 face_list
= get_face_list_from_family(family
);
4709 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4710 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4711 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4712 (face
->scalable
|| can_use_bitmap
))
4714 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4716 font_link
= find_font_link(family
->FamilyName
);
4717 if (font_link
!= NULL
&&
4718 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4725 * Try check the SystemLink list first for a replacement font.
4726 * We may find good replacements there.
4728 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4730 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4731 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4733 TRACE("found entry in system list\n");
4734 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4736 const SYSTEM_LINKS
*links
;
4738 face
= font_link_entry
->face
;
4739 if (!(face
->scalable
|| can_use_bitmap
))
4741 family
= face
->family
;
4742 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4744 links
= find_font_link(family
->FamilyName
);
4745 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4752 psub
= NULL
; /* substitution is no more relevant */
4754 /* If requested charset was DEFAULT_CHARSET then try using charset
4755 corresponding to the current ansi codepage */
4756 if (!csi
.fs
.fsCsb
[0])
4759 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4760 FIXME("TCI failed on codepage %d\n", acp
);
4761 csi
.fs
.fsCsb
[0] = 0;
4763 lf
.lfCharSet
= csi
.ciCharset
;
4766 want_vertical
= (lf
.lfFaceName
[0] == '@');
4768 /* Face families are in the top 4 bits of lfPitchAndFamily,
4769 so mask with 0xF0 before testing */
4771 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4772 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4773 strcpyW(lf
.lfFaceName
, defFixed
);
4774 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4775 strcpyW(lf
.lfFaceName
, defSerif
);
4776 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4777 strcpyW(lf
.lfFaceName
, defSans
);
4779 strcpyW(lf
.lfFaceName
, defSans
);
4780 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4781 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4782 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4783 font_link
= find_font_link(family
->FamilyName
);
4784 face_list
= get_face_list_from_family(family
);
4785 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4786 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4787 if (!(face
->scalable
|| can_use_bitmap
))
4789 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4791 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4797 last_resort_family
= NULL
;
4798 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4799 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4800 font_link
= find_font_link(family
->FamilyName
);
4801 face_list
= get_face_list_from_family(family
);
4802 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4803 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4804 if(face
->vertical
== want_vertical
&&
4805 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4806 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4809 if(can_use_bitmap
&& !last_resort_family
)
4810 last_resort_family
= family
;
4815 if(last_resort_family
) {
4816 family
= last_resort_family
;
4817 csi
.fs
.fsCsb
[0] = 0;
4821 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4822 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4823 face_list
= get_face_list_from_family(family
);
4824 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4825 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4826 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4827 csi
.fs
.fsCsb
[0] = 0;
4828 WARN("just using first face for now\n");
4831 if(can_use_bitmap
&& !last_resort_family
)
4832 last_resort_family
= family
;
4835 if(!last_resort_family
) {
4836 FIXME("can't find a single appropriate font - bailing\n");
4842 WARN("could only find a bitmap font - this will probably look awful!\n");
4843 family
= last_resort_family
;
4844 csi
.fs
.fsCsb
[0] = 0;
4847 it
= lf
.lfItalic
? 1 : 0;
4848 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4850 height
= lf
.lfHeight
;
4852 face
= best
= best_bitmap
= NULL
;
4853 font_link
= find_font_link(family
->FamilyName
);
4854 face_list
= get_face_list_from_family(family
);
4855 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4857 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4858 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4863 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4864 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4865 new_score
= (italic
^ it
) + (bold
^ bd
);
4866 if(!best
|| new_score
<= score
)
4868 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4869 italic
, bold
, it
, bd
);
4872 if(best
->scalable
&& score
== 0) break;
4876 newdiff
= height
- (signed int)(best
->size
.height
);
4878 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4879 if(!best_bitmap
|| new_score
< score
||
4880 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4882 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4885 if(score
== 0 && diff
== 0) break;
4892 face
= best
->scalable
? best
: best_bitmap
;
4893 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4894 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4897 height
= lf
.lfHeight
;
4901 if(csi
.fs
.fsCsb
[0]) {
4902 ret
->charset
= lf
.lfCharSet
;
4903 ret
->codepage
= csi
.ciACP
;
4906 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4908 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4909 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
4911 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4913 if(!face
->scalable
) {
4914 /* Windows uses integer scaling factors for bitmap fonts */
4915 INT scale
, scaled_height
;
4916 GdiFont
*cachedfont
;
4918 /* FIXME: rotation of bitmap fonts is ignored */
4919 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4921 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4922 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4923 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4924 /* As we changed the matrix, we need to search the cache for the font again,
4925 * otherwise we might explode the cache. */
4926 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4927 TRACE("Found cached font after non-scalable matrix rescale!\n");
4932 calc_hash(&ret
->font_desc
);
4934 if (height
!= 0) height
= diff
;
4935 height
+= face
->size
.height
;
4937 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4938 scaled_height
= scale
* face
->size
.height
;
4939 /* Only jump to the next height if the difference <= 25% original height */
4940 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4941 /* The jump between unscaled and doubled is delayed by 1 */
4942 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4943 ret
->scale_y
= scale
;
4945 width
= face
->size
.x_ppem
>> 6;
4946 height
= face
->size
.y_ppem
>> 6;
4950 TRACE("font scale y: %f\n", ret
->scale_y
);
4952 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4961 ret
->ntmFlags
= face
->ntmFlags
;
4963 pick_charmap( ret
->ft_face
, ret
->charset
);
4965 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4966 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4967 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4968 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4969 create_child_font_list(ret
);
4971 if (face
->vertical
) /* We need to try to load the GSUB table */
4973 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4974 if (length
!= GDI_ERROR
)
4976 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4977 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4978 TRACE("Loaded GSUB table of %i bytes\n",length
);
4981 ret
->aa_flags
= face
->aa_flags
;
4983 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4989 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
4991 switch (lf
.lfQuality
)
4993 case NONANTIALIASED_QUALITY
:
4994 case ANTIALIASED_QUALITY
:
4995 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
4997 case CLEARTYPE_QUALITY
:
4998 case CLEARTYPE_NATURAL_QUALITY
:
5000 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5001 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5003 /* fixup the antialiasing flags for that font */
5006 case WINE_GGO_HRGB_BITMAP
:
5007 case WINE_GGO_HBGR_BITMAP
:
5008 case WINE_GGO_VRGB_BITMAP
:
5009 case WINE_GGO_VBGR_BITMAP
:
5010 if (is_subpixel_rendering_enabled()) break;
5011 *aa_flags
= GGO_GRAY4_BITMAP
;
5013 case GGO_GRAY2_BITMAP
:
5014 case GGO_GRAY4_BITMAP
:
5015 case GGO_GRAY8_BITMAP
:
5016 case WINE_GGO_GRAY16_BITMAP
:
5017 if (is_hinting_enabled())
5020 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5022 TRACE( "font %s %d aa disabled by GASP\n",
5023 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5024 *aa_flags
= GGO_BITMAP
;
5029 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5031 physdev
->font
= ret
;
5033 LeaveCriticalSection( &freetype_cs
);
5034 release_dc_ptr( dc
);
5035 return ret
? hfont
: 0;
5038 static void dump_gdi_font_list(void)
5041 struct list
*elem_ptr
;
5043 TRACE("---------- gdiFont Cache ----------\n");
5044 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
5045 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
5046 TRACE("gdiFont=%p %s %d\n",
5047 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
5050 TRACE("---------- Unused gdiFont Cache ----------\n");
5051 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
5052 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
5053 TRACE("gdiFont=%p %s %d\n",
5054 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
5057 TRACE("---------- Child gdiFont Cache ----------\n");
5058 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
5059 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
5060 TRACE("gdiFont=%p %s %d\n",
5061 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
5065 /*************************************************************
5066 * WineEngDestroyFontInstance
5068 * free the gdiFont associated with this handle
5071 BOOL
WineEngDestroyFontInstance(HFONT handle
)
5076 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
5080 EnterCriticalSection( &freetype_cs
);
5082 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
5084 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
5085 while(hfontlist_elem_ptr
) {
5086 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
5087 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
5088 if(hflist
->hfont
== handle
) {
5089 TRACE("removing child font %p from child list\n", gdiFont
);
5090 list_remove(&gdiFont
->entry
);
5091 LeaveCriticalSection( &freetype_cs
);
5097 TRACE("destroying hfont=%p\n", handle
);
5099 dump_gdi_font_list();
5101 font_elem_ptr
= list_head(&gdi_font_list
);
5102 while(font_elem_ptr
) {
5103 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
5104 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
5106 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
5107 while(hfontlist_elem_ptr
) {
5108 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
5109 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
5110 if(hflist
->hfont
== handle
) {
5111 list_remove(&hflist
->entry
);
5112 HeapFree(GetProcessHeap(), 0, hflist
);
5116 if(list_empty(&gdiFont
->hfontlist
)) {
5117 TRACE("Moving to Unused list\n");
5118 list_remove(&gdiFont
->entry
);
5119 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
5124 font_elem_ptr
= list_head(&unused_gdi_font_list
);
5125 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
5126 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
5127 while(font_elem_ptr
) {
5128 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
5129 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
5130 TRACE("freeing %p\n", gdiFont
);
5131 list_remove(&gdiFont
->entry
);
5134 LeaveCriticalSection( &freetype_cs
);
5138 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5145 id
+= IDS_FIRST_SCRIPT
;
5146 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5147 if (!rsrc
) return 0;
5148 hMem
= LoadResource( gdi32_module
, rsrc
);
5149 if (!hMem
) return 0;
5151 p
= LockResource( hMem
);
5153 while (id
--) p
+= *p
+ 1;
5155 i
= min(LF_FACESIZE
- 1, *p
);
5156 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5162 /***************************************************
5163 * create_enum_charset_list
5165 * This function creates charset enumeration list because in DEFAULT_CHARSET
5166 * case, the ANSI codepage's charset takes precedence over other charsets.
5167 * This function works as a filter other than DEFAULT_CHARSET case.
5169 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5174 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5175 csi
.fs
.fsCsb
[0] != 0) {
5176 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5177 list
->element
[n
].charset
= csi
.ciCharset
;
5178 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5181 else { /* charset is DEFAULT_CHARSET or invalid. */
5185 /* Set the current codepage's charset as the first element. */
5187 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5188 csi
.fs
.fsCsb
[0] != 0) {
5189 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5190 list
->element
[n
].charset
= csi
.ciCharset
;
5191 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5192 mask
|= csi
.fs
.fsCsb
[0];
5196 /* Fill out left elements. */
5197 for (i
= 0; i
< 32; i
++) {
5199 fs
.fsCsb
[0] = 1L << i
;
5201 if (fs
.fsCsb
[0] & mask
)
5202 continue; /* skip, already added. */
5203 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5204 continue; /* skip, this is an invalid fsCsb bit. */
5206 list
->element
[n
].mask
= fs
.fsCsb
[0];
5207 list
->element
[n
].charset
= csi
.ciCharset
;
5208 load_script_name( i
, list
->element
[n
].name
);
5209 mask
|= fs
.fsCsb
[0];
5213 /* add catch all mask for remaining bits */
5216 list
->element
[n
].mask
= ~mask
;
5217 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5218 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5227 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
5228 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5233 if (face
->cached_enum_data
)
5236 *pelf
= face
->cached_enum_data
->elf
;
5237 *pntm
= face
->cached_enum_data
->ntm
;
5238 *ptype
= face
->cached_enum_data
->type
;
5242 font
= alloc_font();
5244 if(face
->scalable
) {
5248 height
= face
->size
.y_ppem
>> 6;
5249 width
= face
->size
.x_ppem
>> 6;
5251 font
->scale_y
= 1.0;
5253 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5259 font
->name
= strdupW(face
->family
->FamilyName
);
5260 font
->ntmFlags
= face
->ntmFlags
;
5262 if (get_outline_text_metrics(font
))
5264 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5266 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5267 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5268 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5270 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5271 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5273 lstrcpynW(pelf
->elfFullName
,
5274 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5276 lstrcpynW(pelf
->elfStyle
,
5277 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5282 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5284 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5285 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5286 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5288 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
5290 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5292 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
5293 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5296 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5297 pntm
->ntmFontSig
= face
->fs
;
5299 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5301 pelf
->elfLogFont
.lfEscapement
= 0;
5302 pelf
->elfLogFont
.lfOrientation
= 0;
5303 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5304 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5305 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5306 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5307 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5308 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5309 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5310 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5311 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5312 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5313 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5316 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5317 *ptype
|= TRUETYPE_FONTTYPE
;
5318 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5319 *ptype
|= DEVICE_FONTTYPE
;
5320 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5321 *ptype
|= RASTER_FONTTYPE
;
5323 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5324 if (face
->cached_enum_data
)
5326 face
->cached_enum_data
->elf
= *pelf
;
5327 face
->cached_enum_data
->ntm
= *pntm
;
5328 face
->cached_enum_data
->type
= *ptype
;
5334 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5336 const struct list
*face_list
, *face_elem_ptr
;
5338 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5340 face_list
= get_face_list_from_family(family
);
5341 LIST_FOR_EACH(face_elem_ptr
, face_list
)
5343 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5345 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5351 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5353 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5355 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5358 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5359 FONTENUMPROCW proc
, LPARAM lparam
)
5362 NEWTEXTMETRICEXW ntm
;
5366 GetEnumStructs(face
, &elf
, &ntm
, &type
);
5367 for(i
= 0; i
< list
->total
; i
++) {
5368 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5369 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5370 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5371 i
= list
->total
; /* break out of loop after enumeration */
5375 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5376 /* use the DEFAULT_CHARSET case only if no other charset is present */
5377 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5378 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5379 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5380 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5381 if (!elf
.elfScript
[0])
5382 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5384 /* Font Replacement */
5385 if (family
!= face
->family
)
5387 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5389 strcpyW(elf
.elfFullName
, face
->FullName
);
5391 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5393 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5394 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5395 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5396 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5397 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5398 ntm
.ntmTm
.ntmFlags
);
5399 /* release section before callback (FIXME) */
5400 LeaveCriticalSection( &freetype_cs
);
5401 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5402 EnterCriticalSection( &freetype_cs
);
5407 /*************************************************************
5408 * freetype_EnumFonts
5410 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5414 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
5416 struct enum_charset_list enum_charsets
;
5420 lf
.lfCharSet
= DEFAULT_CHARSET
;
5421 lf
.lfPitchAndFamily
= 0;
5422 lf
.lfFaceName
[0] = 0;
5426 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5428 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5431 EnterCriticalSection( &freetype_cs
);
5432 if(plf
->lfFaceName
[0]) {
5434 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5437 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5438 debugstr_w(psub
->to
.name
));
5440 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5444 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
5445 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
5446 if(family_matches(family
, plf
)) {
5447 face_list
= get_face_list_from_family(family
);
5448 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
5449 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5450 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5451 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5456 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
5457 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
5458 face_list
= get_face_list_from_family(family
);
5459 face_elem_ptr
= list_head(face_list
);
5460 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5461 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5464 LeaveCriticalSection( &freetype_cs
);
5468 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5470 pt
->x
.value
= vec
->x
>> 6;
5471 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5472 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5473 pt
->y
.value
= vec
->y
>> 6;
5474 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5475 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5479 /***************************************************
5480 * According to the MSDN documentation on WideCharToMultiByte,
5481 * certain codepages cannot set the default_used parameter.
5482 * This returns TRUE if the codepage can set that parameter, false else
5483 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5485 static BOOL
codepage_sets_default_used(UINT codepage
)
5499 * GSUB Table handling functions
5502 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5504 const GSUB_CoverageFormat1
* cf1
;
5508 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5510 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5512 TRACE("Coverage Format 1, %i glyphs\n",count
);
5513 for (i
= 0; i
< count
; i
++)
5514 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5518 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5520 const GSUB_CoverageFormat2
* cf2
;
5523 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5525 count
= GET_BE_WORD(cf2
->RangeCount
);
5526 TRACE("Coverage Format 2, %i ranges\n",count
);
5527 for (i
= 0; i
< count
; i
++)
5529 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5531 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5532 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5534 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5535 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5541 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5546 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5548 const GSUB_ScriptList
*script
;
5549 const GSUB_Script
*deflt
= NULL
;
5551 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5553 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5554 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5556 const GSUB_Script
*scr
;
5559 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5560 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5562 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5564 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5570 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5574 const GSUB_LangSys
*Lang
;
5576 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5578 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5580 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5581 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5583 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5586 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5589 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5595 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5598 const GSUB_FeatureList
*feature
;
5599 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5601 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5602 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5604 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5605 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5607 const GSUB_Feature
*feat
;
5608 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5615 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5619 const GSUB_LookupList
*lookup
;
5620 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5622 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5623 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5625 const GSUB_LookupTable
*look
;
5626 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5627 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5628 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5629 if (GET_BE_WORD(look
->LookupType
) != 1)
5630 FIXME("We only handle SubType 1\n");
5635 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5637 const GSUB_SingleSubstFormat1
*ssf1
;
5638 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5639 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5640 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5642 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5643 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5644 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5646 TRACE(" Glyph 0x%x ->",glyph
);
5647 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5648 TRACE(" 0x%x\n",glyph
);
5653 const GSUB_SingleSubstFormat2
*ssf2
;
5657 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5658 offset
= GET_BE_WORD(ssf1
->Coverage
);
5659 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5660 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5661 TRACE(" Coverage index %i\n",index
);
5664 TRACE(" Glyph is 0x%x ->",glyph
);
5665 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5666 TRACE("0x%x\n",glyph
);
5675 static const char* get_opentype_script(const GdiFont
*font
)
5678 * I am not sure if this is the correct way to generate our script tag
5681 switch (font
->charset
)
5683 case ANSI_CHARSET
: return "latn";
5684 case BALTIC_CHARSET
: return "latn"; /* ?? */
5685 case CHINESEBIG5_CHARSET
: return "hani";
5686 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5687 case GB2312_CHARSET
: return "hani";
5688 case GREEK_CHARSET
: return "grek";
5689 case HANGUL_CHARSET
: return "hang";
5690 case RUSSIAN_CHARSET
: return "cyrl";
5691 case SHIFTJIS_CHARSET
: return "kana";
5692 case TURKISH_CHARSET
: return "latn"; /* ?? */
5693 case VIETNAMESE_CHARSET
: return "latn";
5694 case JOHAB_CHARSET
: return "latn"; /* ?? */
5695 case ARABIC_CHARSET
: return "arab";
5696 case HEBREW_CHARSET
: return "hebr";
5697 case THAI_CHARSET
: return "thai";
5698 default: return "latn";
5702 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5704 const GSUB_Header
*header
;
5705 const GSUB_Script
*script
;
5706 const GSUB_LangSys
*language
;
5707 const GSUB_Feature
*feature
;
5709 if (!font
->GSUB_Table
)
5712 header
= font
->GSUB_Table
;
5714 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5717 TRACE("Script not found\n");
5720 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5723 TRACE("Language not found\n");
5726 feature
= GSUB_get_feature(header
, language
, "vrt2");
5728 feature
= GSUB_get_feature(header
, language
, "vert");
5731 TRACE("vrt2/vert feature not found\n");
5734 return GSUB_apply_feature(header
, feature
, glyph
);
5737 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5741 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5742 WCHAR wc
= (WCHAR
)glyph
;
5744 BOOL
*default_used_pointer
;
5747 default_used_pointer
= NULL
;
5748 default_used
= FALSE
;
5749 if (codepage_sets_default_used(font
->codepage
))
5750 default_used_pointer
= &default_used
;
5751 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5753 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
5754 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
5759 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5760 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5764 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5766 if (glyph
< 0x100) glyph
+= 0xf000;
5767 /* there is a number of old pre-Unicode "broken" TTFs, which
5768 do have symbols at U+00XX instead of U+f0XX */
5769 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5770 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5772 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5777 /*************************************************************
5778 * freetype_GetGlyphIndices
5780 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5782 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5785 BOOL got_default
= FALSE
;
5789 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5790 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5793 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5795 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5800 EnterCriticalSection( &freetype_cs
);
5802 for(i
= 0; i
< count
; i
++)
5804 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5809 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5811 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5812 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5817 get_text_metrics(physdev
->font
, &textm
);
5818 default_char
= textm
.tmDefaultChar
;
5822 pgi
[i
] = default_char
;
5825 LeaveCriticalSection( &freetype_cs
);
5829 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5831 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5832 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5835 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5837 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5838 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5841 static inline BYTE
get_max_level( UINT format
)
5845 case GGO_GRAY2_BITMAP
: return 4;
5846 case GGO_GRAY4_BITMAP
: return 16;
5847 case GGO_GRAY8_BITMAP
: return 64;
5852 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5854 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5855 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5858 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5859 FT_Face ft_face
= incoming_font
->ft_face
;
5860 GdiFont
*font
= incoming_font
;
5861 FT_UInt glyph_index
;
5862 DWORD width
, height
, pitch
, needed
= 0;
5863 FT_Bitmap ft_bitmap
;
5865 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5867 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5868 double widthRatio
= 1.0;
5869 FT_Matrix transMat
= identityMat
;
5870 FT_Matrix transMatUnrotated
;
5871 BOOL needsTransform
= FALSE
;
5872 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5873 UINT original_index
;
5875 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5876 buflen
, buf
, lpmat
);
5878 TRACE("font transform %f %f %f %f\n",
5879 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5880 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5882 if(format
& GGO_GLYPH_INDEX
) {
5883 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5884 original_index
= glyph
;
5885 format
&= ~GGO_GLYPH_INDEX
;
5887 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5888 ft_face
= font
->ft_face
;
5889 original_index
= glyph_index
;
5892 if(format
& GGO_UNHINTED
) {
5893 load_flags
|= FT_LOAD_NO_HINTING
;
5894 format
&= ~GGO_UNHINTED
;
5897 /* tategaki never appears to happen to lower glyph index */
5898 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5901 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5902 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5903 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5904 font
->gmsize
* sizeof(GM
*));
5906 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5907 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5909 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5910 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5911 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5912 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5913 return 1; /* FIXME */
5917 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5918 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5920 /* Scaling factor */
5925 get_text_metrics(font
, &tm
);
5927 widthRatio
= (double)font
->aveWidth
;
5928 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5931 widthRatio
= font
->scale_y
;
5933 /* Scaling transform */
5934 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5937 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5940 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5942 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5943 needsTransform
= TRUE
;
5946 /* Slant transform */
5947 if (font
->fake_italic
) {
5950 slantMat
.xx
= (1 << 16);
5951 slantMat
.xy
= ((1 << 16) >> 2);
5953 slantMat
.yy
= (1 << 16);
5954 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5955 needsTransform
= TRUE
;
5958 /* Rotation transform */
5959 transMatUnrotated
= transMat
;
5960 if(font
->orientation
&& !tategaki
) {
5961 FT_Matrix rotationMat
;
5963 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5964 pFT_Vector_Unit(&vecAngle
, angle
);
5965 rotationMat
.xx
= vecAngle
.x
;
5966 rotationMat
.xy
= -vecAngle
.y
;
5967 rotationMat
.yx
= -rotationMat
.xy
;
5968 rotationMat
.yy
= rotationMat
.xx
;
5970 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5971 needsTransform
= TRUE
;
5974 /* World transform */
5975 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5978 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5979 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5980 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5981 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5982 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5983 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5984 needsTransform
= TRUE
;
5987 /* Extra transformation specified by caller */
5988 if (!is_identity_MAT2(lpmat
))
5991 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5992 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5993 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5994 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5995 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5996 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5997 needsTransform
= TRUE
;
6000 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
6001 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
6002 format
== GGO_GRAY8_BITMAP
))
6004 load_flags
|= FT_LOAD_NO_BITMAP
;
6007 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6010 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6014 if(!needsTransform
) {
6015 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
6016 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
6017 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
6019 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
6020 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
6021 ft_face
->glyph
->metrics
.height
) & -64;
6022 lpgm
->gmCellIncX
= adv
;
6023 lpgm
->gmCellIncY
= 0;
6030 for(xc
= 0; xc
< 2; xc
++) {
6031 for(yc
= 0; yc
< 2; yc
++) {
6032 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
6033 xc
* ft_face
->glyph
->metrics
.width
);
6034 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
6035 yc
* ft_face
->glyph
->metrics
.height
;
6036 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6037 pFT_Vector_Transform(&vec
, &transMat
);
6038 if(xc
== 0 && yc
== 0) {
6039 left
= right
= vec
.x
;
6040 top
= bottom
= vec
.y
;
6042 if(vec
.x
< left
) left
= vec
.x
;
6043 else if(vec
.x
> right
) right
= vec
.x
;
6044 if(vec
.y
< bottom
) bottom
= vec
.y
;
6045 else if(vec
.y
> top
) top
= vec
.y
;
6050 right
= (right
+ 63) & -64;
6051 bottom
= bottom
& -64;
6052 top
= (top
+ 63) & -64;
6054 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6055 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
6057 pFT_Vector_Transform(&vec
, &transMat
);
6058 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6059 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6061 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
6063 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6064 adv
= (vec
.x
+63) >> 6;
6068 bbx
= (right
- left
) >> 6;
6069 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6070 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6071 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
6072 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
6074 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6075 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6076 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6078 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6079 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6081 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6082 FONT_GM(font
,original_index
)->adv
= adv
;
6083 FONT_GM(font
,original_index
)->lsb
= lsb
;
6084 FONT_GM(font
,original_index
)->bbx
= bbx
;
6085 FONT_GM(font
,original_index
)->init
= TRUE
;
6088 if(format
== GGO_METRICS
)
6090 return 1; /* FIXME */
6093 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6094 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6096 TRACE("loaded a bitmap\n");
6102 width
= lpgm
->gmBlackBoxX
;
6103 height
= lpgm
->gmBlackBoxY
;
6104 pitch
= ((width
+ 31) >> 5) << 2;
6105 needed
= pitch
* height
;
6107 if(!buf
|| !buflen
) break;
6109 switch(ft_face
->glyph
->format
) {
6110 case ft_glyph_format_bitmap
:
6112 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6113 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
6114 INT h
= ft_face
->glyph
->bitmap
.rows
;
6116 memcpy(dst
, src
, w
);
6117 src
+= ft_face
->glyph
->bitmap
.pitch
;
6123 case ft_glyph_format_outline
:
6124 ft_bitmap
.width
= width
;
6125 ft_bitmap
.rows
= height
;
6126 ft_bitmap
.pitch
= pitch
;
6127 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6128 ft_bitmap
.buffer
= buf
;
6131 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6133 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6135 /* Note: FreeType will only set 'black' bits for us. */
6136 memset(buf
, 0, needed
);
6137 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6141 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6146 case GGO_GRAY2_BITMAP
:
6147 case GGO_GRAY4_BITMAP
:
6148 case GGO_GRAY8_BITMAP
:
6149 case WINE_GGO_GRAY16_BITMAP
:
6151 unsigned int max_level
, row
, col
;
6154 width
= lpgm
->gmBlackBoxX
;
6155 height
= lpgm
->gmBlackBoxY
;
6156 pitch
= (width
+ 3) / 4 * 4;
6157 needed
= pitch
* height
;
6159 if(!buf
|| !buflen
) break;
6161 max_level
= get_max_level( format
);
6163 switch(ft_face
->glyph
->format
) {
6164 case ft_glyph_format_bitmap
:
6166 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6167 INT h
= ft_face
->glyph
->bitmap
.rows
;
6169 memset( buf
, 0, needed
);
6171 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6172 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6173 src
+= ft_face
->glyph
->bitmap
.pitch
;
6178 case ft_glyph_format_outline
:
6180 ft_bitmap
.width
= width
;
6181 ft_bitmap
.rows
= height
;
6182 ft_bitmap
.pitch
= pitch
;
6183 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6184 ft_bitmap
.buffer
= buf
;
6187 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6189 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6191 memset(ft_bitmap
.buffer
, 0, buflen
);
6193 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6195 if (max_level
!= 255)
6197 for (row
= 0, start
= buf
; row
< height
; row
++)
6199 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6200 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6208 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6214 case WINE_GGO_HRGB_BITMAP
:
6215 case WINE_GGO_HBGR_BITMAP
:
6216 case WINE_GGO_VRGB_BITMAP
:
6217 case WINE_GGO_VBGR_BITMAP
:
6218 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6220 switch (ft_face
->glyph
->format
)
6222 case FT_GLYPH_FORMAT_BITMAP
:
6227 width
= lpgm
->gmBlackBoxX
;
6228 height
= lpgm
->gmBlackBoxY
;
6230 needed
= pitch
* height
;
6232 if (!buf
|| !buflen
) break;
6234 memset(buf
, 0, buflen
);
6236 src
= ft_face
->glyph
->bitmap
.buffer
;
6237 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6239 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6242 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6244 if ( src
[x
/ 8] & masks
[x
% 8] )
6245 ((unsigned int *)dst
)[x
] = ~0u;
6254 case FT_GLYPH_FORMAT_OUTLINE
:
6258 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6259 INT x_shift
, y_shift
;
6261 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6262 FT_Render_Mode render_mode
=
6263 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6264 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6266 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6268 if ( render_mode
== FT_RENDER_MODE_LCD
)
6270 lpgm
->gmBlackBoxX
+= 2;
6271 lpgm
->gmptGlyphOrigin
.x
-= 1;
6275 lpgm
->gmBlackBoxY
+= 2;
6276 lpgm
->gmptGlyphOrigin
.y
+= 1;
6280 width
= lpgm
->gmBlackBoxX
;
6281 height
= lpgm
->gmBlackBoxY
;
6283 needed
= pitch
* height
;
6285 if (!buf
|| !buflen
) break;
6287 memset(buf
, 0, buflen
);
6289 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6291 if ( needsTransform
)
6292 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6294 if ( pFT_Library_SetLcdFilter
)
6295 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6296 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6298 src
= ft_face
->glyph
->bitmap
.buffer
;
6299 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6300 src_width
= ft_face
->glyph
->bitmap
.width
;
6301 src_height
= ft_face
->glyph
->bitmap
.rows
;
6303 if ( render_mode
== FT_RENDER_MODE_LCD
)
6311 rgb_interval
= src_pitch
;
6316 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6317 if ( x_shift
< 0 ) x_shift
= 0;
6318 if ( x_shift
+ (src_width
/ hmul
) > width
)
6319 x_shift
= width
- (src_width
/ hmul
);
6321 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6322 if ( y_shift
< 0 ) y_shift
= 0;
6323 if ( y_shift
+ (src_height
/ vmul
) > height
)
6324 y_shift
= height
- (src_height
/ vmul
);
6326 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
6327 while ( src_height
)
6329 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
6333 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6334 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6335 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6336 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6340 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6341 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6342 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6343 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6346 src
+= src_pitch
* vmul
;
6355 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6367 int contour
, point
= 0, first_pt
;
6368 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6369 TTPOLYGONHEADER
*pph
;
6371 DWORD pph_start
, cpfx
, type
;
6373 if(buflen
== 0) buf
= NULL
;
6375 if (needsTransform
&& buf
) {
6376 pFT_Outline_Transform(outline
, &transMat
);
6379 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6381 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6384 pph
->dwType
= TT_POLYGON_TYPE
;
6385 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6387 needed
+= sizeof(*pph
);
6389 while(point
<= outline
->contours
[contour
]) {
6390 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6391 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6392 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6396 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6399 } while(point
<= outline
->contours
[contour
] &&
6400 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6401 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6402 /* At the end of a contour Windows adds the start point, but
6404 if(point
> outline
->contours
[contour
] &&
6405 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6407 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6409 } else if(point
<= outline
->contours
[contour
] &&
6410 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6411 /* add closing pt for bezier */
6413 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6421 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6424 pph
->cb
= needed
- pph_start
;
6430 /* Convert the quadratic Beziers to cubic Beziers.
6431 The parametric eqn for a cubic Bezier is, from PLRM:
6432 r(t) = at^3 + bt^2 + ct + r0
6433 with the control points:
6438 A quadratic Bezier has the form:
6439 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6441 So equating powers of t leads to:
6442 r1 = 2/3 p1 + 1/3 p0
6443 r2 = 2/3 p1 + 1/3 p2
6444 and of course r0 = p0, r3 = p2
6447 int contour
, point
= 0, first_pt
;
6448 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6449 TTPOLYGONHEADER
*pph
;
6451 DWORD pph_start
, cpfx
, type
;
6452 FT_Vector cubic_control
[4];
6453 if(buflen
== 0) buf
= NULL
;
6455 if (needsTransform
&& buf
) {
6456 pFT_Outline_Transform(outline
, &transMat
);
6459 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6461 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6464 pph
->dwType
= TT_POLYGON_TYPE
;
6465 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6467 needed
+= sizeof(*pph
);
6469 while(point
<= outline
->contours
[contour
]) {
6470 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6471 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6472 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6475 if(type
== TT_PRIM_LINE
) {
6477 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6481 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6484 /* FIXME: Possible optimization in endpoint calculation
6485 if there are two consecutive curves */
6486 cubic_control
[0] = outline
->points
[point
-1];
6487 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6488 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6489 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6490 cubic_control
[0].x
>>= 1;
6491 cubic_control
[0].y
>>= 1;
6493 if(point
+1 > outline
->contours
[contour
])
6494 cubic_control
[3] = outline
->points
[first_pt
];
6496 cubic_control
[3] = outline
->points
[point
+1];
6497 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6498 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6499 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6500 cubic_control
[3].x
>>= 1;
6501 cubic_control
[3].y
>>= 1;
6504 /* r1 = 1/3 p0 + 2/3 p1
6505 r2 = 1/3 p2 + 2/3 p1 */
6506 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6507 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6508 cubic_control
[2] = cubic_control
[1];
6509 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6510 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6511 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6512 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6514 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6515 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6516 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6521 } while(point
<= outline
->contours
[contour
] &&
6522 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6523 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6524 /* At the end of a contour Windows adds the start point,
6525 but only for Beziers and we've already done that.
6527 if(point
<= outline
->contours
[contour
] &&
6528 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6529 /* This is the closing pt of a bezier, but we've already
6530 added it, so just inc point and carry on */
6537 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6540 pph
->cb
= needed
- pph_start
;
6546 FIXME("Unsupported format %d\n", format
);
6552 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6554 FT_Face ft_face
= font
->ft_face
;
6555 FT_WinFNT_HeaderRec winfnt_header
;
6556 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6557 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6558 font
->potm
->otmSize
= size
;
6560 #define TM font->potm->otmTextMetrics
6561 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6563 TM
.tmHeight
= winfnt_header
.pixel_height
;
6564 TM
.tmAscent
= winfnt_header
.ascent
;
6565 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6566 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6567 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6568 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6569 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6570 TM
.tmWeight
= winfnt_header
.weight
;
6572 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6573 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6574 TM
.tmFirstChar
= winfnt_header
.first_char
;
6575 TM
.tmLastChar
= winfnt_header
.last_char
;
6576 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6577 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6578 TM
.tmItalic
= winfnt_header
.italic
;
6579 TM
.tmUnderlined
= font
->underline
;
6580 TM
.tmStruckOut
= font
->strikeout
;
6581 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6582 TM
.tmCharSet
= winfnt_header
.charset
;
6586 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6587 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6588 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6589 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6590 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6591 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6592 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6593 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6595 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6596 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6598 TM
.tmLastChar
= 255;
6599 TM
.tmDefaultChar
= 32;
6600 TM
.tmBreakChar
= 32;
6601 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6602 TM
.tmUnderlined
= font
->underline
;
6603 TM
.tmStruckOut
= font
->strikeout
;
6604 /* NB inverted meaning of TMPF_FIXED_PITCH */
6605 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6606 TM
.tmCharSet
= font
->charset
;
6614 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6616 double scale_x
, scale_y
;
6620 scale_x
= (double)font
->aveWidth
;
6621 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6624 scale_x
= font
->scale_y
;
6626 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6627 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6629 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6630 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6632 SCALE_Y(ptm
->tmHeight
);
6633 SCALE_Y(ptm
->tmAscent
);
6634 SCALE_Y(ptm
->tmDescent
);
6635 SCALE_Y(ptm
->tmInternalLeading
);
6636 SCALE_Y(ptm
->tmExternalLeading
);
6637 SCALE_Y(ptm
->tmOverhang
);
6639 SCALE_X(ptm
->tmAveCharWidth
);
6640 SCALE_X(ptm
->tmMaxCharWidth
);
6646 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6648 double scale_x
, scale_y
;
6652 scale_x
= (double)font
->aveWidth
;
6653 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6656 scale_x
= font
->scale_y
;
6658 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6659 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6661 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6663 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6664 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6666 SCALE_Y(potm
->otmAscent
);
6667 SCALE_Y(potm
->otmDescent
);
6668 SCALE_Y(potm
->otmLineGap
);
6669 SCALE_Y(potm
->otmsCapEmHeight
);
6670 SCALE_Y(potm
->otmsXHeight
);
6671 SCALE_Y(potm
->otmrcFontBox
.top
);
6672 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6673 SCALE_X(potm
->otmrcFontBox
.left
);
6674 SCALE_X(potm
->otmrcFontBox
.right
);
6675 SCALE_Y(potm
->otmMacAscent
);
6676 SCALE_Y(potm
->otmMacDescent
);
6677 SCALE_Y(potm
->otmMacLineGap
);
6678 SCALE_X(potm
->otmptSubscriptSize
.x
);
6679 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6680 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6681 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6682 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6683 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6684 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6685 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6686 SCALE_Y(potm
->otmsStrikeoutSize
);
6687 SCALE_Y(potm
->otmsStrikeoutPosition
);
6688 SCALE_Y(potm
->otmsUnderscoreSize
);
6689 SCALE_Y(potm
->otmsUnderscorePosition
);
6695 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6699 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6701 /* Make sure that the font has sane width/height ratio */
6704 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6706 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6711 *ptm
= font
->potm
->otmTextMetrics
;
6712 scale_font_metrics(font
, ptm
);
6716 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6720 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6722 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6728 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6731 FT_Face ft_face
= font
->ft_face
;
6732 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
6734 TT_HoriHeader
*pHori
;
6735 TT_Postscript
*pPost
;
6736 FT_Fixed x_scale
, y_scale
;
6737 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
6739 INT ascent
, descent
;
6741 TRACE("font=%p\n", font
);
6743 if(!FT_IS_SCALABLE(ft_face
))
6746 needed
= sizeof(*font
->potm
);
6748 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6749 family_nameW
= strdupW(font
->name
);
6751 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
6753 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6756 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6757 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
6759 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
6761 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
6763 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6766 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6767 face_nameW
= strdupW(font
->name
);
6769 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
6770 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
6772 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
6774 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6777 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
6778 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6779 full_nameW
= strdupW(fake_nameW
);
6781 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
6783 /* These names should be read from the TT name table */
6785 /* length of otmpFamilyName */
6788 /* length of otmpFaceName */
6791 /* length of otmpStyleName */
6794 /* length of otmpFullName */
6798 x_scale
= ft_face
->size
->metrics
.x_scale
;
6799 y_scale
= ft_face
->size
->metrics
.y_scale
;
6801 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6803 FIXME("Can't find OS/2 table - not TT font?\n");
6807 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6809 FIXME("Can't find HHEA table - not TT font?\n");
6813 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6815 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",
6816 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6817 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6818 pOS2
->xAvgCharWidth
,
6819 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6820 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6821 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6823 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6824 font
->potm
->otmSize
= needed
;
6826 #define TM font->potm->otmTextMetrics
6828 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6829 ascent
= pHori
->Ascender
;
6830 descent
= -pHori
->Descender
;
6832 ascent
= pOS2
->usWinAscent
;
6833 descent
= pOS2
->usWinDescent
;
6836 font
->ntmCellHeight
= ascent
+ descent
;
6837 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6840 TM
.tmAscent
= font
->yMax
;
6841 TM
.tmDescent
= -font
->yMin
;
6842 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6844 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6845 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6846 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6847 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6850 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6853 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6855 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6856 ((ascent
+ descent
) -
6857 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6859 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6860 if (TM
.tmAveCharWidth
== 0) {
6861 TM
.tmAveCharWidth
= 1;
6863 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6864 TM
.tmWeight
= FW_REGULAR
;
6865 if (font
->fake_bold
)
6866 TM
.tmWeight
= FW_BOLD
;
6869 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6871 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6872 TM
.tmWeight
= pOS2
->usWeightClass
;
6874 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6875 TM
.tmWeight
= pOS2
->usWeightClass
;
6878 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6879 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6880 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6881 * symbol range to 0 - f0ff
6884 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6889 case 1257: /* Baltic */
6890 TM
.tmLastChar
= 0xf8fd;
6893 TM
.tmLastChar
= 0xf0ff;
6895 TM
.tmBreakChar
= 0x20;
6896 TM
.tmDefaultChar
= 0x1f;
6900 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6901 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6903 if(pOS2
->usFirstCharIndex
<= 1)
6904 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6905 else if (pOS2
->usFirstCharIndex
> 0xff)
6906 TM
.tmBreakChar
= 0x20;
6908 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6909 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6911 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6912 TM
.tmUnderlined
= font
->underline
;
6913 TM
.tmStruckOut
= font
->strikeout
;
6915 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6916 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6917 (pOS2
->version
== 0xFFFFU
||
6918 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6919 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6921 TM
.tmPitchAndFamily
= 0;
6923 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6925 case PAN_FAMILY_SCRIPT
:
6926 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6929 case PAN_FAMILY_DECORATIVE
:
6930 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6935 case PAN_FAMILY_TEXT_DISPLAY
:
6936 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6937 /* which is clearly not what the panose spec says. */
6939 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6940 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6941 TM
.tmPitchAndFamily
= FF_MODERN
;
6944 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6949 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6952 case PAN_SERIF_COVE
:
6953 case PAN_SERIF_OBTUSE_COVE
:
6954 case PAN_SERIF_SQUARE_COVE
:
6955 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6956 case PAN_SERIF_SQUARE
:
6957 case PAN_SERIF_THIN
:
6958 case PAN_SERIF_BONE
:
6959 case PAN_SERIF_EXAGGERATED
:
6960 case PAN_SERIF_TRIANGLE
:
6961 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6964 case PAN_SERIF_NORMAL_SANS
:
6965 case PAN_SERIF_OBTUSE_SANS
:
6966 case PAN_SERIF_PERP_SANS
:
6967 case PAN_SERIF_FLARED
:
6968 case PAN_SERIF_ROUNDED
:
6969 TM
.tmPitchAndFamily
|= FF_SWISS
;
6976 if(FT_IS_SCALABLE(ft_face
))
6977 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6979 if(FT_IS_SFNT(ft_face
))
6981 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6982 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6984 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6987 TM
.tmCharSet
= font
->charset
;
6989 font
->potm
->otmFiller
= 0;
6990 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6991 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6992 font
->potm
->otmfsType
= pOS2
->fsType
;
6993 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6994 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6995 font
->potm
->otmItalicAngle
= 0; /* POST table */
6996 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6997 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6998 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6999 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
7000 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
7001 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
7002 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
7003 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
7004 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
7005 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
7006 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7007 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7008 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7009 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7010 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
7011 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
7012 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
7013 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
7014 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
7015 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
7016 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
7017 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
7018 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
7019 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
7021 font
->potm
->otmsUnderscoreSize
= 0;
7022 font
->potm
->otmsUnderscorePosition
= 0;
7024 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
7025 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
7029 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7030 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7031 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7032 strcpyW((WCHAR
*)cp
, family_nameW
);
7034 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7035 strcpyW((WCHAR
*)cp
, style_nameW
);
7037 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7038 strcpyW((WCHAR
*)cp
, face_nameW
);
7040 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7041 strcpyW((WCHAR
*)cp
, full_nameW
);
7045 HeapFree(GetProcessHeap(), 0, style_nameW
);
7046 HeapFree(GetProcessHeap(), 0, family_nameW
);
7047 HeapFree(GetProcessHeap(), 0, face_nameW
);
7048 HeapFree(GetProcessHeap(), 0, full_nameW
);
7052 /*************************************************************
7053 * freetype_GetGlyphOutline
7055 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7056 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7058 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7063 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7064 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7068 EnterCriticalSection( &freetype_cs
);
7069 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7070 LeaveCriticalSection( &freetype_cs
);
7074 /*************************************************************
7075 * freetype_GetTextMetrics
7077 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7079 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7084 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7085 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7089 EnterCriticalSection( &freetype_cs
);
7090 ret
= get_text_metrics( physdev
->font
, metrics
);
7091 LeaveCriticalSection( &freetype_cs
);
7095 /*************************************************************
7096 * freetype_GetOutlineTextMetrics
7098 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7100 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7105 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7106 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7109 TRACE("font=%p\n", physdev
->font
);
7111 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7114 EnterCriticalSection( &freetype_cs
);
7116 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7118 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7120 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7121 scale_outline_font_metrics(physdev
->font
, potm
);
7123 ret
= physdev
->font
->potm
->otmSize
;
7125 LeaveCriticalSection( &freetype_cs
);
7129 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7131 HFONTLIST
*hfontlist
;
7132 child
->font
= alloc_font();
7133 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7134 if(!child
->font
->ft_face
)
7136 free_font(child
->font
);
7141 child
->font
->font_desc
= font
->font_desc
;
7142 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7143 child
->font
->orientation
= font
->orientation
;
7144 child
->font
->scale_y
= font
->scale_y
;
7145 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
7146 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
7147 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7148 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
7149 child
->font
->base_font
= font
;
7150 list_add_head(&child_font_list
, &child
->font
->entry
);
7151 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
7155 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
7158 CHILD_FONT
*child_font
;
7161 font
= font
->base_font
;
7163 *linked_font
= font
;
7165 if((*glyph
= get_glyph_index(font
, c
)))
7167 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7171 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7173 if(!child_font
->font
)
7174 if(!load_child_font(font
, child_font
))
7177 if(!child_font
->font
->ft_face
)
7179 g
= get_glyph_index(child_font
->font
, c
);
7180 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7184 *linked_font
= child_font
->font
;
7191 /*************************************************************
7192 * freetype_GetCharWidth
7194 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7196 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7199 FT_UInt glyph_index
;
7200 GdiFont
*linked_font
;
7201 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7205 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7206 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7209 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7212 EnterCriticalSection( &freetype_cs
);
7213 for(c
= firstChar
; c
<= lastChar
; c
++) {
7214 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
7215 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7216 &gm
, 0, NULL
, &identity
);
7217 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
7219 LeaveCriticalSection( &freetype_cs
);
7223 /*************************************************************
7224 * freetype_GetCharABCWidths
7226 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7228 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7231 FT_UInt glyph_index
;
7232 GdiFont
*linked_font
;
7233 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7237 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7238 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7241 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7244 EnterCriticalSection( &freetype_cs
);
7246 for(c
= firstChar
; c
<= lastChar
; c
++) {
7247 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
7248 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7249 &gm
, 0, NULL
, &identity
);
7250 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
7251 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
7252 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
7253 FONT_GM(linked_font
,glyph_index
)->bbx
;
7255 LeaveCriticalSection( &freetype_cs
);
7259 /*************************************************************
7260 * freetype_GetCharABCWidthsI
7262 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7264 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7267 FT_UInt glyph_index
;
7268 GdiFont
*linked_font
;
7269 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7273 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7274 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7277 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7281 EnterCriticalSection( &freetype_cs
);
7283 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
7285 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
7286 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7287 &gm
, 0, NULL
, &identity
);
7288 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
7289 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
7290 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
7291 - FONT_GM(linked_font
,c
)->bbx
;
7294 for(c
= 0; c
< count
; c
++) {
7295 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7296 &gm
, 0, NULL
, &identity
);
7297 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
7298 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
7299 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
7300 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
7303 LeaveCriticalSection( &freetype_cs
);
7307 /*************************************************************
7308 * freetype_GetTextExtentExPoint
7310 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
7311 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
7313 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7318 FT_UInt glyph_index
;
7319 GdiFont
*linked_font
;
7320 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7324 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7325 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
7328 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
7331 EnterCriticalSection( &freetype_cs
);
7334 get_text_metrics( physdev
->font
, &tm
);
7335 size
->cy
= tm
.tmHeight
;
7337 for(idx
= 0; idx
< count
; idx
++) {
7338 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
7339 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7340 &gm
, 0, NULL
, &identity
);
7341 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
7343 if (! pnfit
|| ext
<= max_ext
) {
7353 LeaveCriticalSection( &freetype_cs
);
7354 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
7358 /*************************************************************
7359 * freetype_GetTextExtentExPointI
7361 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
7362 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
7364 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7369 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7373 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7374 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
7377 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
7380 EnterCriticalSection( &freetype_cs
);
7383 get_text_metrics(physdev
->font
, &tm
);
7384 size
->cy
= tm
.tmHeight
;
7386 for(idx
= 0; idx
< count
; idx
++) {
7387 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
7388 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
7390 if (! pnfit
|| ext
<= max_ext
) {
7400 LeaveCriticalSection( &freetype_cs
);
7401 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
7405 /*************************************************************
7406 * freetype_GetFontData
7408 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7410 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7414 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7415 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7418 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7419 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7420 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7422 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7425 /*************************************************************
7426 * freetype_GetTextFace
7428 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7431 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7435 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7436 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7439 n
= strlenW(physdev
->font
->name
) + 1;
7442 lstrcpynW(str
, physdev
->font
->name
, count
);
7448 /*************************************************************
7449 * freetype_GetTextCharsetInfo
7451 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7453 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7457 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7458 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7460 if (fs
) *fs
= physdev
->font
->fs
;
7461 return physdev
->font
->charset
;
7464 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7466 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
7467 struct list
*first_hfont
;
7471 EnterCriticalSection( &freetype_cs
);
7472 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
7473 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
7474 if(font
== linked_font
)
7475 *new_hfont
= dc
->hFont
;
7478 first_hfont
= list_head(&linked_font
->hfontlist
);
7479 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
7481 LeaveCriticalSection( &freetype_cs
);
7485 /* Retrieve a list of supported Unicode ranges for a given font.
7486 * Can be called with NULL gs to calculate the buffer size. Returns
7487 * the number of ranges found.
7489 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7491 DWORD num_ranges
= 0;
7493 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7496 FT_ULong char_code
, char_code_prev
;
7499 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7501 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7502 face
->num_glyphs
, glyph_code
, char_code
);
7504 if (!glyph_code
) return 0;
7508 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7509 gs
->ranges
[0].cGlyphs
= 0;
7510 gs
->cGlyphsSupported
= 0;
7516 if (char_code
< char_code_prev
)
7518 ERR("expected increasing char code from FT_Get_Next_Char\n");
7521 if (char_code
- char_code_prev
> 1)
7526 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7527 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7528 gs
->cGlyphsSupported
++;
7533 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7534 gs
->cGlyphsSupported
++;
7536 char_code_prev
= char_code
;
7537 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7541 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7546 /*************************************************************
7547 * freetype_GetFontUnicodeRanges
7549 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7551 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7552 DWORD size
, num_ranges
;
7556 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7557 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7560 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7561 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7564 glyphset
->cbThis
= size
;
7565 glyphset
->cRanges
= num_ranges
;
7566 glyphset
->flAccel
= 0;
7571 /*************************************************************
7572 * freetype_FontIsLinked
7574 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7576 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7581 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7582 return dev
->funcs
->pFontIsLinked( dev
);
7586 EnterCriticalSection( &freetype_cs
);
7587 ret
= !list_empty(&physdev
->font
->child_fonts
);
7588 LeaveCriticalSection( &freetype_cs
);
7592 /*************************************************************************
7593 * GetRasterizerCaps (GDI32.@)
7595 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7597 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7598 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7599 lprs
->nLanguageID
= 0;
7603 /*************************************************************
7604 * freetype_GdiRealizationInfo
7606 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7608 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7609 realization_info_t
*info
= ptr
;
7613 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7614 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7617 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7620 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7623 info
->cache_num
= physdev
->font
->cache_num
;
7624 info
->unknown2
= -1;
7628 /*************************************************************************
7629 * Kerning support for TrueType fonts
7631 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7633 struct TT_kern_table
7639 struct TT_kern_subtable
7648 USHORT horizontal
: 1;
7650 USHORT cross_stream
: 1;
7651 USHORT override
: 1;
7652 USHORT reserved1
: 4;
7658 struct TT_format0_kern_subtable
7662 USHORT entrySelector
;
7673 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7674 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7675 const USHORT
*glyph_to_char
,
7676 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7679 const struct TT_kern_pair
*tt_kern_pair
;
7681 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7683 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7685 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7686 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7687 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7689 if (!kern_pair
|| !cPairs
)
7692 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7694 nPairs
= min(nPairs
, cPairs
);
7696 for (i
= 0; i
< nPairs
; i
++)
7698 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7699 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7700 /* this algorithm appears to better match what Windows does */
7701 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7702 if (kern_pair
->iKernAmount
< 0)
7704 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7705 kern_pair
->iKernAmount
-= font
->ppem
;
7707 else if (kern_pair
->iKernAmount
> 0)
7709 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7710 kern_pair
->iKernAmount
+= font
->ppem
;
7712 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7714 TRACE("left %u right %u value %d\n",
7715 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7719 TRACE("copied %u entries\n", nPairs
);
7723 /*************************************************************
7724 * freetype_GetKerningPairs
7726 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7730 const struct TT_kern_table
*tt_kern_table
;
7731 const struct TT_kern_subtable
*tt_kern_subtable
;
7733 USHORT
*glyph_to_char
;
7735 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7737 if (!(font
= physdev
->font
))
7739 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7740 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7744 EnterCriticalSection( &freetype_cs
);
7745 if (font
->total_kern_pairs
!= (DWORD
)-1)
7747 if (cPairs
&& kern_pair
)
7749 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7750 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7752 else cPairs
= font
->total_kern_pairs
;
7754 LeaveCriticalSection( &freetype_cs
);
7758 font
->total_kern_pairs
= 0;
7760 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7762 if (length
== GDI_ERROR
)
7764 TRACE("no kerning data in the font\n");
7765 LeaveCriticalSection( &freetype_cs
);
7769 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7772 WARN("Out of memory\n");
7773 LeaveCriticalSection( &freetype_cs
);
7777 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7779 /* build a glyph index to char code map */
7780 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7783 WARN("Out of memory allocating a glyph index to char code map\n");
7784 HeapFree(GetProcessHeap(), 0, buf
);
7785 LeaveCriticalSection( &freetype_cs
);
7789 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7795 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7797 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7798 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7802 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7804 /* FIXME: This doesn't match what Windows does: it does some fancy
7805 * things with duplicate glyph index to char code mappings, while
7806 * we just avoid overriding existing entries.
7808 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7809 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7811 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7818 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7819 for (n
= 0; n
<= 65535; n
++)
7820 glyph_to_char
[n
] = (USHORT
)n
;
7823 tt_kern_table
= buf
;
7824 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7825 TRACE("version %u, nTables %u\n",
7826 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7828 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7830 for (i
= 0; i
< nTables
; i
++)
7832 struct TT_kern_subtable tt_kern_subtable_copy
;
7834 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7835 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7836 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7838 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7839 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7840 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7842 /* According to the TrueType specification this is the only format
7843 * that will be properly interpreted by Windows and OS/2
7845 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7847 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7849 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7850 glyph_to_char
, NULL
, 0);
7851 font
->total_kern_pairs
+= new_chunk
;
7853 if (!font
->kern_pairs
)
7854 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7855 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7857 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7858 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7860 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7861 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7864 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7866 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7869 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7870 HeapFree(GetProcessHeap(), 0, buf
);
7872 if (cPairs
&& kern_pair
)
7874 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7875 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7877 else cPairs
= font
->total_kern_pairs
;
7879 LeaveCriticalSection( &freetype_cs
);
7883 static const struct gdi_dc_funcs freetype_funcs
=
7885 NULL
, /* pAbortDoc */
7886 NULL
, /* pAbortPath */
7887 NULL
, /* pAlphaBlend */
7888 NULL
, /* pAngleArc */
7891 NULL
, /* pBeginPath */
7892 NULL
, /* pBlendImage */
7894 NULL
, /* pCloseFigure */
7895 NULL
, /* pCreateCompatibleDC */
7896 freetype_CreateDC
, /* pCreateDC */
7897 freetype_DeleteDC
, /* pDeleteDC */
7898 NULL
, /* pDeleteObject */
7899 NULL
, /* pDeviceCapabilities */
7900 NULL
, /* pEllipse */
7902 NULL
, /* pEndPage */
7903 NULL
, /* pEndPath */
7904 freetype_EnumFonts
, /* pEnumFonts */
7905 NULL
, /* pEnumICMProfiles */
7906 NULL
, /* pExcludeClipRect */
7907 NULL
, /* pExtDeviceMode */
7908 NULL
, /* pExtEscape */
7909 NULL
, /* pExtFloodFill */
7910 NULL
, /* pExtSelectClipRgn */
7911 NULL
, /* pExtTextOut */
7912 NULL
, /* pFillPath */
7913 NULL
, /* pFillRgn */
7914 NULL
, /* pFlattenPath */
7915 freetype_FontIsLinked
, /* pFontIsLinked */
7916 NULL
, /* pFrameRgn */
7917 NULL
, /* pGdiComment */
7918 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7919 NULL
, /* pGetBoundsRect */
7920 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7921 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7922 freetype_GetCharWidth
, /* pGetCharWidth */
7923 NULL
, /* pGetDeviceCaps */
7924 NULL
, /* pGetDeviceGammaRamp */
7925 freetype_GetFontData
, /* pGetFontData */
7926 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7927 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7928 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7929 NULL
, /* pGetICMProfile */
7930 NULL
, /* pGetImage */
7931 freetype_GetKerningPairs
, /* pGetKerningPairs */
7932 NULL
, /* pGetNearestColor */
7933 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7934 NULL
, /* pGetPixel */
7935 NULL
, /* pGetSystemPaletteEntries */
7936 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7937 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7938 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7939 freetype_GetTextFace
, /* pGetTextFace */
7940 freetype_GetTextMetrics
, /* pGetTextMetrics */
7941 NULL
, /* pGradientFill */
7942 NULL
, /* pIntersectClipRect */
7943 NULL
, /* pInvertRgn */
7945 NULL
, /* pModifyWorldTransform */
7947 NULL
, /* pOffsetClipRgn */
7948 NULL
, /* pOffsetViewportOrg */
7949 NULL
, /* pOffsetWindowOrg */
7950 NULL
, /* pPaintRgn */
7953 NULL
, /* pPolyBezier */
7954 NULL
, /* pPolyBezierTo */
7955 NULL
, /* pPolyDraw */
7956 NULL
, /* pPolyPolygon */
7957 NULL
, /* pPolyPolyline */
7958 NULL
, /* pPolygon */
7959 NULL
, /* pPolyline */
7960 NULL
, /* pPolylineTo */
7961 NULL
, /* pPutImage */
7962 NULL
, /* pRealizeDefaultPalette */
7963 NULL
, /* pRealizePalette */
7964 NULL
, /* pRectangle */
7965 NULL
, /* pResetDC */
7966 NULL
, /* pRestoreDC */
7967 NULL
, /* pRoundRect */
7969 NULL
, /* pScaleViewportExt */
7970 NULL
, /* pScaleWindowExt */
7971 NULL
, /* pSelectBitmap */
7972 NULL
, /* pSelectBrush */
7973 NULL
, /* pSelectClipPath */
7974 freetype_SelectFont
, /* pSelectFont */
7975 NULL
, /* pSelectPalette */
7976 NULL
, /* pSelectPen */
7977 NULL
, /* pSetArcDirection */
7978 NULL
, /* pSetBkColor */
7979 NULL
, /* pSetBkMode */
7980 NULL
, /* pSetDCBrushColor */
7981 NULL
, /* pSetDCPenColor */
7982 NULL
, /* pSetDIBColorTable */
7983 NULL
, /* pSetDIBitsToDevice */
7984 NULL
, /* pSetDeviceClipping */
7985 NULL
, /* pSetDeviceGammaRamp */
7986 NULL
, /* pSetLayout */
7987 NULL
, /* pSetMapMode */
7988 NULL
, /* pSetMapperFlags */
7989 NULL
, /* pSetPixel */
7990 NULL
, /* pSetPolyFillMode */
7991 NULL
, /* pSetROP2 */
7992 NULL
, /* pSetRelAbs */
7993 NULL
, /* pSetStretchBltMode */
7994 NULL
, /* pSetTextAlign */
7995 NULL
, /* pSetTextCharacterExtra */
7996 NULL
, /* pSetTextColor */
7997 NULL
, /* pSetTextJustification */
7998 NULL
, /* pSetViewportExt */
7999 NULL
, /* pSetViewportOrg */
8000 NULL
, /* pSetWindowExt */
8001 NULL
, /* pSetWindowOrg */
8002 NULL
, /* pSetWorldTransform */
8003 NULL
, /* pStartDoc */
8004 NULL
, /* pStartPage */
8005 NULL
, /* pStretchBlt */
8006 NULL
, /* pStretchDIBits */
8007 NULL
, /* pStrokeAndFillPath */
8008 NULL
, /* pStrokePath */
8009 NULL
, /* pUnrealizePalette */
8010 NULL
, /* pWidenPath */
8011 NULL
, /* wine_get_wgl_driver */
8012 GDI_PRIORITY_FONT_DRV
/* priority */
8015 #else /* HAVE_FREETYPE */
8017 /*************************************************************************/
8019 BOOL
WineEngInit(void)
8023 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
8028 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8030 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8034 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8036 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8040 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8042 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8046 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8047 LPCWSTR font_file
, LPCWSTR font_path
)
8053 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
8058 /*************************************************************************
8059 * GetRasterizerCaps (GDI32.@)
8061 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8063 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8065 lprs
->nLanguageID
= 0;
8069 #endif /* HAVE_FREETYPE */