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(FcConfigGetCurrent
);
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(FcPatternGetString
);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading
;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height
, width
;
249 FT_Pos size
, x_ppem
, y_ppem
;
255 NEWTEXTMETRICEXW ntm
;
259 typedef struct tagFace
{
265 DWORD font_data_size
;
269 FT_Fixed font_version
;
272 Bitmap_Size size
; /* set if face is a bitmap */
273 BOOL external
; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily
*family
;
275 /* Cached data for Enum */
276 struct enum_data
*cached_enum_data
;
279 typedef struct tagFamily
{
281 const WCHAR
*FamilyName
;
282 const WCHAR
*EnglishName
;
284 struct list
*replacement
;
289 INT adv
; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST
{
322 struct list hfontlist
;
323 OUTLINETEXTMETRICW
*potm
;
324 DWORD total_kern_pairs
;
325 KERNINGPAIR
*kern_pairs
;
326 struct list child_fonts
;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping
*mapping
;
353 const WCHAR
*font_name
;
358 struct enum_charset_element
{
361 WCHAR name
[LF_FACESIZE
];
364 struct enum_charset_list
{
366 struct enum_charset_element element
[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
373 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list
= LIST_INIT(child_font_list
);
376 static struct list system_links
= LIST_INIT(system_links
);
378 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
380 static struct list font_list
= LIST_INIT(font_list
);
382 struct freetype_physdev
384 struct gdi_physdev dev
;
388 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
390 return (struct freetype_physdev
*)dev
;
393 static const struct gdi_dc_funcs freetype_funcs
;
395 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR
* const SystemFontValues
[] = {
422 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 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 };
428 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial
[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 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};
438 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};
439 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR
*default_serif_list
[] =
450 bitstream_vera_serif
,
454 static const WCHAR
*default_fixed_list
[] =
458 bitstream_vera_sans_mono
,
462 static const WCHAR
*default_sans_list
[] =
475 typedef struct tagFontSubst
{
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value
[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value
[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value
[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 static struct list mappings_list
= LIST_INIT( mappings_list
);
513 static CRITICAL_SECTION freetype_cs
;
514 static CRITICAL_SECTION_DEBUG critsect_debug
=
517 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
518 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback
= FALSE
;
527 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
528 static BOOL
get_outline_text_metrics(GdiFont
*font
);
529 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
531 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
547 * FIXEDFON.FON FixedSys
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
589 GSUB_ScriptRecord ScriptRecord
[1];
595 } GSUB_LangSysRecord
;
600 GSUB_LangSysRecord LangSysRecord
[1];
604 WORD LookupOrder
; /* Reserved */
605 WORD ReqFeatureIndex
;
607 WORD FeatureIndex
[1];
613 } GSUB_FeatureRecord
;
617 GSUB_FeatureRecord FeatureRecord
[1];
621 WORD FeatureParams
; /* Reserved */
623 WORD LookupListIndex
[1];
642 } GSUB_CoverageFormat1
;
647 WORD StartCoverageIndex
;
653 GSUB_RangeRecord RangeRecord
[1];
654 } GSUB_CoverageFormat2
;
657 WORD SubstFormat
; /* = 1 */
660 } GSUB_SingleSubstFormat1
;
663 WORD SubstFormat
; /* = 2 */
667 }GSUB_SingleSubstFormat2
;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
674 static char cached_path
[MAX_PATH
];
675 static const char *wine
= "/Wine", *fonts
= "/Fonts";
677 if(*cached_path
) return cached_path
;
679 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
682 WARN("can't create cached data folder\n");
685 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
688 WARN("can't create cached data path\n");
692 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
694 ERR("Could not create full path\n");
698 strcat(cached_path
, wine
);
700 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
702 WARN("Couldn't mkdir %s\n", cached_path
);
706 strcat(cached_path
, fonts
);
707 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
709 WARN("Couldn't mkdir %s\n", cached_path
);
716 /******************************************************************
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path
)
734 const char *filename
;
738 unsigned int size
, max_size
;
741 TRACE("path %s\n", path
);
743 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
746 WARN("failed to get ref\n");
750 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
757 TRACE("unable to open resource fork\n");
764 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
767 CloseResFile(res_ref
);
771 out_dir
= find_cache_dir();
773 filename
= strrchr(path
, '/');
774 if(!filename
) filename
= path
;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
785 unsigned short *num_faces_ptr
, num_faces
, face
;
788 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
790 fond
= Get1IndResource(fond_res
, idx
);
792 TRACE("got fond resource %d\n", idx
);
795 fam_rec
= *(FamRec
**)fond
;
796 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
797 num_faces
= GET_BE_WORD(*num_faces_ptr
);
799 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
800 TRACE("num faces %04x\n", num_faces
);
801 for(face
= 0; face
< num_faces
; face
++, assoc
++)
804 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
805 unsigned short size
, font_id
;
808 size
= GET_BE_WORD(assoc
->fontSize
);
809 font_id
= GET_BE_WORD(assoc
->fontID
);
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
816 TRACE("trying to load sfnt id %04x\n", font_id
);
817 sfnt
= GetResource(sfnt_res
, font_id
);
820 TRACE("can't get sfnt resource %04x\n", font_id
);
824 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
829 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
831 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
832 if(fd
!= -1 || errno
== EEXIST
)
836 unsigned char *sfnt_data
;
839 sfnt_data
= *(unsigned char**)sfnt
;
840 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
844 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
847 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
849 ret
.array
[ret
.size
++] = output
;
853 WARN("unable to create %s\n", output
);
854 HeapFree(GetProcessHeap(), 0, output
);
857 ReleaseResource(sfnt
);
860 ReleaseResource(fond
);
863 CloseResFile(res_ref
);
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL
is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed
FT_FixedFromFloat(double f
)
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
889 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
893 static const struct list
*get_face_list_from_family(const Family
*family
)
895 if (!list_empty(&family
->faces
))
896 return &family
->faces
;
898 return family
->replacement
;
901 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
906 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
907 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
909 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
912 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
914 const struct list
*face_list
;
915 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
917 face_list
= get_face_list_from_family(family
);
918 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
922 file
= strrchr(face
->file
, '/');
927 if(!strcasecmp(file
, file_nameA
))
929 HeapFree(GetProcessHeap(), 0, file_nameA
);
934 HeapFree(GetProcessHeap(), 0, file_nameA
);
938 static Family
*find_family_from_name(const WCHAR
*name
)
942 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
944 if(!strcmpiW(family
->FamilyName
, name
))
951 static Family
*find_family_from_any_name(const WCHAR
*name
)
955 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
957 if(!strcmpiW(family
->FamilyName
, name
))
959 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
966 static void DumpSubstList(void)
970 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
972 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
974 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
976 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
977 debugstr_w(psub
->to
.name
));
982 static LPWSTR
strdupW(LPCWSTR p
)
985 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
986 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
991 static LPSTR
strdupA(LPCSTR p
)
994 DWORD len
= (strlen(p
) + 1);
995 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1000 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1005 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1007 if(!strcmpiW(element
->from
.name
, from_name
) &&
1008 (element
->from
.charset
== from_charset
||
1009 element
->from
.charset
== -1))
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1020 FontSubst
*from_exist
, *to_exist
;
1022 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1024 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1026 list_remove(&from_exist
->entry
);
1027 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
1028 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
1029 HeapFree(GetProcessHeap(), 0, from_exist
);
1035 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1039 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1040 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1043 list_add_tail(subst_list
, &subst
->entry
);
1048 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1049 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1050 HeapFree(GetProcessHeap(), 0, subst
);
1054 static WCHAR
*towstr(UINT cp
, const char *str
)
1059 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1060 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1061 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1065 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1067 CHAR
*p
= strrchr(str
, ',');
1071 nc
->charset
= strtol(p
+1, NULL
, 10);
1074 nc
->name
= towstr(CP_ACP
, str
);
1077 static void LoadSubstList(void)
1081 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey
) == ERROR_SUCCESS
) {
1089 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1090 &valuelen
, &datalen
, NULL
, NULL
);
1092 valuelen
++; /* returned value doesn't include room for '\0' */
1093 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1094 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1098 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1099 &dlen
) == ERROR_SUCCESS
) {
1100 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1102 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1103 split_subst_info(&psub
->from
, value
);
1104 split_subst_info(&psub
->to
, data
);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1109 psub
->to
.charset
== DEFAULT_CHARSET
) {
1110 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1111 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1112 HeapFree(GetProcessHeap(), 0, psub
);
1114 add_font_subst(&font_subst_list
, psub
, 0);
1116 /* reset dlen and vlen */
1120 HeapFree(GetProcessHeap(), 0, data
);
1121 HeapFree(GetProcessHeap(), 0, value
);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1138 FT_UInt num_names
, name_index
;
1140 if(FT_IS_SFNT(ft_face
))
1142 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1144 for(name_index
= 0; name_index
< num_names
; name_index
++)
1146 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1148 if((name
.platform_id
== req
->platform_id
) &&
1149 (name
.encoding_id
== req
->encoding_id
) &&
1150 (name
.language_id
== req
->language_id
) &&
1151 (name
.name_id
== req
->name_id
))
1153 req
->string
= name
.string
;
1154 req
->string_len
= name
.string_len
;
1161 req
->string_len
= 0;
1165 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1170 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1171 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1172 name
.language_id
= language_id
;
1173 name
.name_id
= name_id
;
1175 if(get_name_table_entry(ft_face
, &name
))
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1181 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1183 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1184 ret
[i
] = GET_BE_WORD(*tmp
);
1187 TRACE("Got localised name %s\n", debugstr_w(ret
));
1193 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1196 LONG r
= RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, &needed
);
1197 if(r
!= ERROR_SUCCESS
) return r
;
1198 if(type
!= REG_DWORD
|| needed
!= sizeof(DWORD
)) return ERROR_BAD_CONFIGURATION
;
1199 return RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &needed
);
1202 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1204 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1207 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
)
1210 DWORD num_strikes
, max_strike_key_len
;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1218 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1219 face
->cached_enum_data
= NULL
;
1221 face
->file
= HeapAlloc(GetProcessHeap(), 0, needed
);
1222 RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, (BYTE
*)face
->file
, &needed
);
1224 face
->StyleName
= strdupW(face_name
);
1225 face
->family
= family
;
1226 face
->vertical
= (family
->FamilyName
[0] == '@');
1228 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1230 WCHAR
*fullName
= HeapAlloc(GetProcessHeap(), 0, needed
);
1231 RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, (BYTE
*)fullName
, &needed
);
1232 face
->FullName
= fullName
;
1235 face
->FullName
= NULL
;
1237 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1238 reg_load_dword(hkey_face
, face_italic_value
, &italic
);
1239 reg_load_dword(hkey_face
, face_bold_value
, &bold
);
1240 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1241 reg_load_dword(hkey_face
, face_external_value
, (DWORD
*)&face
->external
);
1243 needed
= sizeof(face
->fs
);
1244 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1246 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1248 face
->scalable
= TRUE
;
1249 memset(&face
->size
, 0, sizeof(face
->size
));
1253 face
->scalable
= FALSE
;
1254 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1255 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1256 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1257 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1258 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1262 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1266 if (italic
) face
->ntmFlags
|= NTM_ITALIC
;
1267 if (bold
) face
->ntmFlags
|= NTM_BOLD
;
1268 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1272 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1273 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1275 if(!italic
&& !bold
)
1276 list_add_head(&family
->faces
, &face
->entry
);
1278 list_add_tail(&family
->faces
, &face
->entry
);
1280 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face
, NULL
, NULL
, NULL
, &num_strikes
, &max_strike_key_len
, NULL
, NULL
,
1285 NULL
, NULL
, NULL
, NULL
);
1286 if(num_strikes
!= 0)
1288 WCHAR strike_name
[10];
1289 DWORD strike_index
= 0;
1291 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1292 while(RegEnumKeyExW(hkey_face
, strike_index
++, strike_name
, &needed
,
1293 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1296 RegOpenKeyExW(hkey_face
, strike_name
, 0, KEY_ALL_ACCESS
, &hkey_strike
);
1297 load_face(hkey_strike
, face_name
, family
);
1298 RegCloseKey(hkey_strike
);
1299 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1306 DWORD max_family_key_len
, size
;
1308 DWORD family_index
= 0;
1312 RegQueryInfoKeyW(hkey_font_cache
, NULL
, NULL
, NULL
, NULL
, &max_family_key_len
, NULL
, NULL
,
1313 NULL
, NULL
, NULL
, NULL
);
1314 family_name
= HeapAlloc(GetProcessHeap(), 0, (max_family_key_len
+ 1) * sizeof(WCHAR
));
1316 size
= max_family_key_len
+ 1;
1317 while(RegEnumKeyExW(hkey_font_cache
, family_index
++, family_name
, &size
,
1318 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1320 WCHAR
*english_family
= NULL
;
1321 DWORD face_index
= 0;
1323 DWORD max_face_key_len
;
1325 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1326 TRACE("opened family key %s\n", debugstr_w(family_name
));
1327 if(RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, NULL
, &size
) == ERROR_SUCCESS
)
1329 english_family
= HeapAlloc(GetProcessHeap(), 0, size
);
1330 RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)english_family
, &size
);
1333 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1334 family
->FamilyName
= strdupW(family_name
);
1335 family
->EnglishName
= english_family
;
1336 list_init(&family
->faces
);
1337 family
->replacement
= &family
->faces
;
1338 list_add_tail(&font_list
, &family
->entry
);
1342 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1343 subst
->from
.name
= strdupW(english_family
);
1344 subst
->from
.charset
= -1;
1345 subst
->to
.name
= strdupW(family_name
);
1346 subst
->to
.charset
= -1;
1347 add_font_subst(&font_subst_list
, subst
, 0);
1350 RegQueryInfoKeyW(hkey_family
, NULL
, NULL
, NULL
, NULL
, &max_face_key_len
, NULL
, NULL
,
1351 NULL
, NULL
, NULL
, NULL
);
1353 face_name
= HeapAlloc(GetProcessHeap(), 0, (max_face_key_len
+ 1) * sizeof(WCHAR
));
1354 size
= max_face_key_len
+ 1;
1355 while(RegEnumKeyExW(hkey_family
, face_index
++, face_name
, &size
,
1356 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1360 RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
);
1361 load_face(hkey_face
, face_name
, family
);
1362 RegCloseKey(hkey_face
);
1363 size
= max_face_key_len
+ 1;
1365 HeapFree(GetProcessHeap(), 0, face_name
);
1366 RegCloseKey(hkey_family
);
1367 size
= max_family_key_len
+ 1;
1370 HeapFree(GetProcessHeap(), 0, family_name
);
1373 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1376 HKEY hkey_wine_fonts
;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1380 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1381 if(ret
!= ERROR_SUCCESS
)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1387 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1388 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1389 RegCloseKey(hkey_wine_fonts
);
1393 static void add_face_to_cache(Face
*face
)
1395 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1396 WCHAR
*face_key_name
;
1398 create_font_cache_key(&hkey_font_cache
, NULL
);
1400 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1401 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1402 if(face
->family
->EnglishName
)
1403 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1404 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1407 face_key_name
= face
->StyleName
;
1410 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1411 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1412 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1414 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1417 HeapFree(GetProcessHeap(), 0, face_key_name
);
1419 RegSetValueExA(hkey_face
, "File Name", 0, REG_BINARY
, (BYTE
*)face
->file
, strlen(face
->file
) + 1);
1421 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1422 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1424 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1425 reg_save_dword(hkey_face
, face_italic_value
, (face
->ntmFlags
& NTM_ITALIC
) != 0);
1426 reg_save_dword(hkey_face
, face_bold_value
, (face
->ntmFlags
& NTM_BOLD
) != 0);
1427 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1428 reg_save_dword(hkey_face
, face_external_value
, face
->external
);
1430 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1434 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1435 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1436 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1437 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1438 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1439 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1441 RegCloseKey(hkey_face
);
1442 RegCloseKey(hkey_family
);
1443 RegCloseKey(hkey_font_cache
);
1446 static inline int TestStyles(DWORD flags
, DWORD styles
)
1448 return (flags
& styles
) == styles
;
1451 static inline int style_order(Face
*face
)
1453 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1455 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1457 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1459 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face
->family
->FamilyName
),
1464 debugstr_w(face
->StyleName
),
1470 static WCHAR
*prepend_at(WCHAR
*family
)
1477 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1479 strcpyW(str
+ 1, family
);
1480 HeapFree(GetProcessHeap(), 0, family
);
1484 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1486 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1487 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1489 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID() );
1495 else if (!strcmpiW( *name
, *english
))
1497 HeapFree( GetProcessHeap(), 0, *english
);
1503 *name
= prepend_at( *name
);
1504 *english
= prepend_at( *english
);
1508 /****************************************************************
1509 * NB This function stores the ptrs to the strings to save copying.
1510 * Don't free them after calling.
1512 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1514 Family
*family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1515 family
->FamilyName
= name
;
1516 family
->EnglishName
= english_name
;
1517 list_init( &family
->faces
);
1518 family
->replacement
= &family
->faces
;
1523 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1526 WCHAR
*name
, *english_name
;
1528 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1530 family
= find_family_from_name( name
);
1534 family
= create_family( name
, english_name
);
1535 list_add_tail( &font_list
, &family
->entry
);
1539 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1540 subst
->from
.name
= strdupW( english_name
);
1541 subst
->from
.charset
= -1;
1542 subst
->to
.name
= strdupW( name
);
1543 subst
->to
.charset
= -1;
1544 add_font_subst( &font_subst_list
, subst
, 0 );
1549 HeapFree( GetProcessHeap(), 0, name
);
1550 HeapFree( GetProcessHeap(), 0, english_name
);
1556 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1558 FT_Fixed version
= 0;
1561 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1562 if (header
) version
= header
->Font_Revision
;
1567 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1570 FT_ULong table_size
= 0;
1572 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1573 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1574 if (flags
== 0) flags
= NTM_REGULAR
;
1576 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1577 flags
|= NTM_PS_OPENTYPE
;
1582 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1584 int internal_leading
= 0;
1585 FT_WinFNT_HeaderRec winfnt_header
;
1587 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1588 internal_leading
= winfnt_header
.internal_leading
;
1590 return internal_leading
;
1593 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1598 FT_WinFNT_HeaderRec winfnt_header
;
1601 memset( fs
, 0, sizeof(*fs
) );
1603 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1606 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1607 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1608 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1609 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1611 if (os2
->version
== 0)
1613 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1614 fs
->fsCsb
[0] = FS_LATIN1
;
1616 fs
->fsCsb
[0] = FS_SYMBOL
;
1620 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1621 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1626 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1628 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1629 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1630 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1635 if (fs
->fsCsb
[0] == 0)
1637 /* let's see if we can find any interesting cmaps */
1638 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1640 switch (ft_face
->charmaps
[i
]->encoding
)
1642 case FT_ENCODING_UNICODE
:
1643 case FT_ENCODING_APPLE_ROMAN
:
1644 fs
->fsCsb
[0] |= FS_LATIN1
;
1646 case FT_ENCODING_MS_SYMBOL
:
1647 fs
->fsCsb
[0] |= FS_SYMBOL
;
1656 static inline void free_face( Face
*face
)
1658 HeapFree( GetProcessHeap(), 0, face
->file
);
1659 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1660 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1661 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1662 HeapFree( GetProcessHeap(), 0, face
);
1665 #define ADDFONT_EXTERNAL_FONT 0x01
1666 #define ADDFONT_FORCE_BITMAP 0x02
1667 #define ADDFONT_ADD_TO_CACHE 0x04
1669 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1670 DWORD flags
, BOOL vertical
)
1672 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1673 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1675 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1676 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1679 face
->file
= strdupA( file
);
1680 face
->font_data_ptr
= NULL
;
1681 face
->font_data_size
= 0;
1686 face
->font_data_ptr
= font_data_ptr
;
1687 face
->font_data_size
= font_data_size
;
1690 face
->face_index
= face_index
;
1691 get_fontsig( ft_face
, &face
->fs
);
1692 face
->ntmFlags
= get_ntm_flags( ft_face
);
1693 face
->font_version
= get_font_version( ft_face
);
1695 if (FT_IS_SCALABLE( ft_face
))
1697 memset( &face
->size
, 0, sizeof(face
->size
) );
1698 face
->scalable
= TRUE
;
1702 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1703 size
->height
, size
->width
, size
->size
>> 6,
1704 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1705 face
->size
.height
= size
->height
;
1706 face
->size
.width
= size
->width
;
1707 face
->size
.size
= size
->size
;
1708 face
->size
.x_ppem
= size
->x_ppem
;
1709 face
->size
.y_ppem
= size
->y_ppem
;
1710 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1711 face
->scalable
= FALSE
;
1714 face
->vertical
= vertical
;
1715 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1716 face
->family
= NULL
;
1717 face
->cached_enum_data
= NULL
;
1719 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1720 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1721 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1722 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1727 static inline BOOL
faces_equal( Face
*f1
, Face
*f2
)
1729 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1730 if (f1
->scalable
) return TRUE
;
1731 if (f2
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1732 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1735 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1739 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1741 if (faces_equal( face
, cursor
))
1743 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1744 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1745 cursor
->font_version
, face
->font_version
);
1747 if (face
->font_version
<= cursor
->font_version
)
1749 TRACE("Original font is newer so skipping this one\n");
1754 TRACE("Replacing original with this one\n");
1755 list_add_before( &cursor
->entry
, &face
->entry
);
1756 face
->family
= family
;
1757 list_remove( &cursor
->entry
);
1758 free_face( cursor
);
1763 if (style_order( face
) < style_order( cursor
)) break;
1766 list_add_before( &cursor
->entry
, &face
->entry
);
1767 face
->family
= family
;
1771 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1772 FT_Long face_index
, DWORD flags
, BOOL vertical
)
1777 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
, vertical
);
1778 family
= get_family( ft_face
, vertical
);
1779 if (!insert_face_in_family_list( face
, family
))
1785 if (flags
& ADDFONT_ADD_TO_CACHE
)
1786 add_face_to_cache( face
);
1788 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1789 debugstr_w(face
->StyleName
));
1792 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1797 FT_Long face_index
= 0, num_faces
;
1800 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1801 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1803 #ifdef HAVE_CARBON_CARBON_H
1806 char **mac_list
= expand_mac_font(file
);
1809 BOOL had_one
= FALSE
;
1811 for(cursor
= mac_list
; *cursor
; cursor
++)
1814 AddFontToList(*cursor
, NULL
, 0, flags
);
1815 HeapFree(GetProcessHeap(), 0, *cursor
);
1817 HeapFree(GetProcessHeap(), 0, mac_list
);
1822 #endif /* HAVE_CARBON_CARBON_H */
1827 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1828 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1831 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1832 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1836 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1840 if(!FT_IS_SFNT(ft_face
) && (FT_IS_SCALABLE(ft_face
) || !(flags
& ADDFONT_FORCE_BITMAP
))) { /* for now we'll accept TT/OT or bitmap fonts*/
1841 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1842 pFT_Done_Face(ft_face
);
1846 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1847 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1848 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1849 pFT_Done_Face(ft_face
);
1853 if(FT_IS_SFNT(ft_face
))
1855 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1856 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1857 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
))
1859 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1860 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1861 pFT_Done_Face(ft_face
);
1865 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1866 we don't want to load these. */
1867 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1871 if(!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1873 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1874 pFT_Done_Face(ft_face
);
1880 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1881 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1882 pFT_Done_Face(ft_face
);
1886 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1888 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1889 pFT_Done_Face(ft_face
);
1893 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1896 if (FT_HAS_VERTICAL(ft_face
))
1898 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1902 num_faces
= ft_face
->num_faces
;
1903 pFT_Done_Face(ft_face
);
1904 } while(num_faces
> ++face_index
);
1908 static void DumpFontList(void)
1912 struct list
*family_elem_ptr
, *face_elem_ptr
;
1914 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1915 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1916 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1917 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1918 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1919 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1921 TRACE(" %d", face
->size
.height
);
1928 /***********************************************************
1929 * The replacement list is a way to map an entire font
1930 * family onto another family. For example adding
1932 * [HKCU\Software\Wine\Fonts\Replacements]
1933 * "Wingdings"="Winedings"
1935 * would enumerate the Winedings font both as Winedings and
1936 * Wingdings. However if a real Wingdings font is present the
1937 * replacement does not take place.
1940 static void LoadReplaceList(void)
1943 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1948 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1949 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1951 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1952 &valuelen
, &datalen
, NULL
, NULL
);
1954 valuelen
++; /* returned value doesn't include room for '\0' */
1955 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1956 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1960 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1961 &dlen
) == ERROR_SUCCESS
) {
1962 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1963 /* "NewName"="Oldname" */
1964 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1966 if(!find_family_from_any_name(value
))
1968 Family
* const family
= find_family_from_any_name(data
);
1971 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
1972 if (new_family
!= NULL
)
1974 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
1975 new_family
->FamilyName
= strdupW(value
);
1976 new_family
->EnglishName
= NULL
;
1977 list_init(&new_family
->faces
);
1978 new_family
->replacement
= &family
->faces
;
1979 list_add_tail(&font_list
, &new_family
->entry
);
1984 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
1989 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
1991 /* reset dlen and vlen */
1995 HeapFree(GetProcessHeap(), 0, data
);
1996 HeapFree(GetProcessHeap(), 0, value
);
2001 static const WCHAR
*font_links_list
[] =
2003 Lucida_Sans_Unicode
,
2004 Microsoft_Sans_Serif
,
2008 static const struct font_links_defaults_list
2010 /* Keyed off substitution for "MS Shell Dlg" */
2011 const WCHAR
*shelldlg
;
2012 /* Maximum of four substitutes, plus terminating NULL pointer */
2013 const WCHAR
*substitutes
[5];
2014 } font_links_defaults_list
[] =
2016 /* Non East-Asian */
2017 { Tahoma
, /* FIXME unverified ordering */
2018 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2020 /* Below lists are courtesy of
2021 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2025 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2027 /* Chinese Simplified */
2029 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2033 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2035 /* Chinese Traditional */
2037 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2042 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2044 SYSTEM_LINKS
*font_link
;
2046 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2048 if(!strcmpiW(font_link
->font_name
, name
))
2055 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2067 SYSTEM_LINKS
*font_link
;
2069 psub
= get_font_subst(&font_subst_list
, name
, -1);
2070 /* Don't store fonts that are only substitutes for other fonts */
2073 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2077 font_link
= find_font_link(name
);
2078 if (font_link
== NULL
)
2080 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2081 font_link
->font_name
= strdupW(name
);
2082 list_init(&font_link
->links
);
2083 list_add_tail(&system_links
, &font_link
->entry
);
2086 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2087 for (i
= 0; values
[i
] != NULL
; i
++)
2089 const struct list
*face_list
;
2090 CHILD_FONT
*child_font
;
2093 if (!strcmpiW(name
,value
))
2095 psub
= get_font_subst(&font_subst_list
, value
, -1);
2097 value
= psub
->to
.name
;
2098 family
= find_family_from_name(value
);
2102 /* Use first extant filename for this Family */
2103 face_list
= get_face_list_from_family(family
);
2104 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2108 file
= strrchr(face
->file
, '/');
2117 fileW
= towstr(CP_UNIXCP
, file
);
2119 face
= find_face_from_filename(fileW
, value
);
2122 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2126 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2127 child_font
->face
= face
;
2128 child_font
->font
= NULL
;
2129 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2130 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2131 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2132 list_add_tail(&font_link
->links
, &child_font
->entry
);
2134 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2135 HeapFree(GetProcessHeap(), 0, fileW
);
2141 /*************************************************************
2144 static BOOL
init_system_links(void)
2148 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2149 WCHAR
*value
, *data
;
2150 WCHAR
*entry
, *next
;
2151 SYSTEM_LINKS
*font_link
, *system_font_link
;
2152 CHILD_FONT
*child_font
;
2153 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2154 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2155 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2160 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2162 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2163 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2164 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2165 val_len
= max_val
+ 1;
2166 data_len
= max_data
;
2168 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2170 psub
= get_font_subst(&font_subst_list
, value
, -1);
2171 /* Don't store fonts that are only substitutes for other fonts */
2174 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2177 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2178 font_link
->font_name
= strdupW(value
);
2179 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2180 list_init(&font_link
->links
);
2181 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2184 CHILD_FONT
*child_font
;
2186 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2188 next
= entry
+ strlenW(entry
) + 1;
2190 face_name
= strchrW(entry
, ',');
2194 while(isspaceW(*face_name
))
2197 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2199 face_name
= psub
->to
.name
;
2201 face
= find_face_from_filename(entry
, face_name
);
2204 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2208 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2209 child_font
->face
= face
;
2210 child_font
->font
= NULL
;
2211 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2212 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2213 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2214 list_add_tail(&font_link
->links
, &child_font
->entry
);
2216 list_add_tail(&system_links
, &font_link
->entry
);
2218 val_len
= max_val
+ 1;
2219 data_len
= max_data
;
2222 HeapFree(GetProcessHeap(), 0, value
);
2223 HeapFree(GetProcessHeap(), 0, data
);
2228 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2230 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2234 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2236 const FontSubst
*psub2
;
2237 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2239 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2241 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2242 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2244 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2245 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2247 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2249 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2255 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2258 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2259 system_font_link
->font_name
= strdupW(System
);
2260 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2261 list_init(&system_font_link
->links
);
2263 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2266 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2267 child_font
->face
= face
;
2268 child_font
->font
= NULL
;
2269 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2270 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2271 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2272 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2274 font_link
= find_font_link(Tahoma
);
2275 if (font_link
!= NULL
)
2277 CHILD_FONT
*font_link_entry
;
2278 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2280 CHILD_FONT
*new_child
;
2281 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2282 new_child
->face
= font_link_entry
->face
;
2283 new_child
->font
= NULL
;
2284 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2285 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2286 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2289 list_add_tail(&system_links
, &system_font_link
->entry
);
2293 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2296 struct dirent
*dent
;
2297 char path
[MAX_PATH
];
2299 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2301 dir
= opendir(dirname
);
2303 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2306 while((dent
= readdir(dir
)) != NULL
) {
2307 struct stat statbuf
;
2309 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2312 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2314 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2316 if(stat(path
, &statbuf
) == -1)
2318 WARN("Can't stat %s\n", debugstr_a(path
));
2321 if(S_ISDIR(statbuf
.st_mode
))
2322 ReadFontDir(path
, external_fonts
);
2325 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2326 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2327 AddFontToList(path
, NULL
, 0, addfont_flags
);
2334 static void load_fontconfig_fonts(void)
2336 #ifdef SONAME_LIBFONTCONFIG
2337 void *fc_handle
= NULL
;
2346 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2348 TRACE("Wine cannot find the fontconfig library (%s).\n",
2349 SONAME_LIBFONTCONFIG
);
2352 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2353 LOAD_FUNCPTR(FcConfigGetCurrent
);
2354 LOAD_FUNCPTR(FcFontList
);
2355 LOAD_FUNCPTR(FcFontSetDestroy
);
2356 LOAD_FUNCPTR(FcInit
);
2357 LOAD_FUNCPTR(FcObjectSetAdd
);
2358 LOAD_FUNCPTR(FcObjectSetCreate
);
2359 LOAD_FUNCPTR(FcObjectSetDestroy
);
2360 LOAD_FUNCPTR(FcPatternCreate
);
2361 LOAD_FUNCPTR(FcPatternDestroy
);
2362 LOAD_FUNCPTR(FcPatternGetBool
);
2363 LOAD_FUNCPTR(FcPatternGetString
);
2366 if(!pFcInit()) return;
2368 config
= pFcConfigGetCurrent();
2369 pat
= pFcPatternCreate();
2370 os
= pFcObjectSetCreate();
2371 pFcObjectSetAdd(os
, FC_FILE
);
2372 pFcObjectSetAdd(os
, FC_SCALABLE
);
2373 fontset
= pFcFontList(config
, pat
, os
);
2374 if(!fontset
) return;
2375 for(i
= 0; i
< fontset
->nfont
; i
++) {
2378 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2380 TRACE("fontconfig: %s\n", file
);
2382 /* We're just interested in OT/TT fonts for now, so this hack just
2383 picks up the scalable fonts without extensions .pf[ab] to save time
2384 loading every other font */
2386 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2388 TRACE("not scalable\n");
2392 len
= strlen( file
);
2393 if(len
< 4) continue;
2394 ext
= &file
[ len
- 3 ];
2395 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2396 AddFontToList(file
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2398 pFcFontSetDestroy(fontset
);
2399 pFcObjectSetDestroy(os
);
2400 pFcPatternDestroy(pat
);
2406 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2409 const char *data_dir
= wine_get_data_dir();
2411 if (!data_dir
) data_dir
= wine_get_build_dir();
2418 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2420 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2422 strcpy(unix_name
, data_dir
);
2423 strcat(unix_name
, "/fonts/");
2425 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2427 EnterCriticalSection( &freetype_cs
);
2428 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2429 LeaveCriticalSection( &freetype_cs
);
2430 HeapFree(GetProcessHeap(), 0, unix_name
);
2435 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2437 static const WCHAR slashW
[] = {'\\','\0'};
2439 WCHAR windowsdir
[MAX_PATH
];
2442 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2443 strcatW(windowsdir
, fontsW
);
2444 strcatW(windowsdir
, slashW
);
2445 strcatW(windowsdir
, file
);
2446 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2447 EnterCriticalSection( &freetype_cs
);
2448 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2449 LeaveCriticalSection( &freetype_cs
);
2450 HeapFree(GetProcessHeap(), 0, unixname
);
2455 static void load_system_fonts(void)
2458 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2459 const WCHAR
* const *value
;
2461 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2464 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2465 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2466 strcatW(windowsdir
, fontsW
);
2467 for(value
= SystemFontValues
; *value
; value
++) {
2468 dlen
= sizeof(data
);
2469 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2473 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2474 if((unixname
= wine_get_unix_file_name(pathW
))) {
2475 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2476 HeapFree(GetProcessHeap(), 0, unixname
);
2479 load_font_from_data_dir(data
);
2486 /*************************************************************
2488 * This adds registry entries for any externally loaded fonts
2489 * (fonts from fontconfig or FontDirs). It also deletes entries
2490 * of no longer existing fonts.
2493 static void update_reg_entries(void)
2495 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2500 struct list
*family_elem_ptr
, *face_elem_ptr
;
2502 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2503 static const WCHAR spaceW
[] = {' ', '\0'};
2506 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2507 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2508 ERR("Can't create Windows font reg key\n");
2512 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2513 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2514 ERR("Can't create Windows font reg key\n");
2518 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2519 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2520 ERR("Can't create external font reg key\n");
2524 /* enumerate the fonts and add external ones to the two keys */
2526 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2527 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2528 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2529 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2530 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2531 if(!face
->external
) continue;
2533 if (!(face
->ntmFlags
& NTM_REGULAR
))
2534 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2535 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2536 strcpyW(valueW
, family
->FamilyName
);
2537 if(len
!= len_fam
) {
2538 strcatW(valueW
, spaceW
);
2539 strcatW(valueW
, face
->StyleName
);
2541 strcatW(valueW
, TrueType
);
2543 file
= wine_get_dos_file_name(face
->file
);
2545 len
= strlenW(file
) + 1;
2548 if((path
= strrchr(face
->file
, '/')) == NULL
)
2552 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2554 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2555 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2557 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2558 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2559 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2561 HeapFree(GetProcessHeap(), 0, file
);
2562 HeapFree(GetProcessHeap(), 0, valueW
);
2566 if(external_key
) RegCloseKey(external_key
);
2567 if(win9x_key
) RegCloseKey(win9x_key
);
2568 if(winnt_key
) RegCloseKey(winnt_key
);
2572 static void delete_external_font_keys(void)
2574 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2575 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2579 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2580 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2581 ERR("Can't create Windows font reg key\n");
2585 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2586 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2587 ERR("Can't create Windows font reg key\n");
2591 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2592 ERR("Can't create external font reg key\n");
2596 /* Delete all external fonts added last time */
2598 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2599 &valuelen
, &datalen
, NULL
, NULL
);
2600 valuelen
++; /* returned value doesn't include room for '\0' */
2601 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2602 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2604 dlen
= datalen
* sizeof(WCHAR
);
2607 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2608 &dlen
) == ERROR_SUCCESS
) {
2610 RegDeleteValueW(winnt_key
, valueW
);
2611 RegDeleteValueW(win9x_key
, valueW
);
2612 /* reset dlen and vlen */
2616 HeapFree(GetProcessHeap(), 0, data
);
2617 HeapFree(GetProcessHeap(), 0, valueW
);
2619 /* Delete the old external fonts key */
2620 RegCloseKey(external_key
);
2621 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2624 if(win9x_key
) RegCloseKey(win9x_key
);
2625 if(winnt_key
) RegCloseKey(winnt_key
);
2628 /*************************************************************
2629 * WineEngAddFontResourceEx
2632 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2638 if (ft_handle
) /* do it only if we have freetype up and running */
2643 FIXME("Ignoring flags %x\n", flags
);
2645 if((unixname
= wine_get_unix_file_name(file
)))
2647 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2649 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2650 EnterCriticalSection( &freetype_cs
);
2651 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2652 LeaveCriticalSection( &freetype_cs
);
2653 HeapFree(GetProcessHeap(), 0, unixname
);
2655 if (!ret
&& !strchrW(file
, '\\')) {
2656 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2657 ret
= load_font_from_winfonts_dir(file
);
2659 /* Try in datadir/fonts (or builddir/fonts),
2660 * needed for Magic the Gathering Online
2662 ret
= load_font_from_data_dir(file
);
2669 /*************************************************************
2670 * WineEngAddFontMemResourceEx
2673 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2677 if (ft_handle
) /* do it only if we have freetype up and running */
2679 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2681 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2682 memcpy(pFontCopy
, pbFont
, cbFont
);
2684 EnterCriticalSection( &freetype_cs
);
2685 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2686 LeaveCriticalSection( &freetype_cs
);
2690 TRACE("AddFontToList failed\n");
2691 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2694 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2695 * For now return something unique but quite random
2697 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2698 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2705 /*************************************************************
2706 * WineEngRemoveFontResourceEx
2709 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2712 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2716 static const struct nls_update_font_list
2718 UINT ansi_cp
, oem_cp
;
2719 const char *oem
, *fixed
, *system
;
2720 const char *courier
, *serif
, *small
, *sserif
;
2721 /* these are for font substitutes */
2722 const char *shelldlg
, *tmsrmn
;
2723 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2727 const char *from
, *to
;
2728 } arial_0
, courier_new_0
, times_new_roman_0
;
2729 } nls_update_font_list
[] =
2731 /* Latin 1 (United States) */
2732 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2733 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2734 "Tahoma","Times New Roman",
2735 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2738 /* Latin 1 (Multilingual) */
2739 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2740 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2741 "Tahoma","Times New Roman", /* FIXME unverified */
2742 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2745 /* Eastern Europe */
2746 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2747 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2748 "Tahoma","Times New Roman", /* FIXME unverified */
2749 "Fixedsys,238", "System,238",
2750 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2751 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2752 { "Arial CE,0", "Arial,238" },
2753 { "Courier New CE,0", "Courier New,238" },
2754 { "Times New Roman CE,0", "Times New Roman,238" }
2757 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2758 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2759 "Tahoma","Times New Roman", /* FIXME unverified */
2760 "Fixedsys,204", "System,204",
2761 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2762 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2763 { "Arial Cyr,0", "Arial,204" },
2764 { "Courier New Cyr,0", "Courier New,204" },
2765 { "Times New Roman Cyr,0", "Times New Roman,204" }
2768 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2769 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2770 "Tahoma","Times New Roman", /* FIXME unverified */
2771 "Fixedsys,161", "System,161",
2772 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2773 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2774 { "Arial Greek,0", "Arial,161" },
2775 { "Courier New Greek,0", "Courier New,161" },
2776 { "Times New Roman Greek,0", "Times New Roman,161" }
2779 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2780 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2781 "Tahoma","Times New Roman", /* FIXME unverified */
2782 "Fixedsys,162", "System,162",
2783 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2784 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2785 { "Arial Tur,0", "Arial,162" },
2786 { "Courier New Tur,0", "Courier New,162" },
2787 { "Times New Roman Tur,0", "Times New Roman,162" }
2790 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2791 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2792 "Tahoma","Times New Roman", /* FIXME unverified */
2793 "Fixedsys,177", "System,177",
2794 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2795 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2799 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2800 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2801 "Tahoma","Times New Roman", /* FIXME unverified */
2802 "Fixedsys,178", "System,178",
2803 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2804 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2808 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2809 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2810 "Tahoma","Times New Roman", /* FIXME unverified */
2811 "Fixedsys,186", "System,186",
2812 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2813 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2814 { "Arial Baltic,0", "Arial,186" },
2815 { "Courier New Baltic,0", "Courier New,186" },
2816 { "Times New Roman Baltic,0", "Times New Roman,186" }
2819 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2820 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2821 "Tahoma","Times New Roman", /* FIXME unverified */
2822 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2826 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2827 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2828 "Tahoma","Times New Roman", /* FIXME unverified */
2829 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2833 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2834 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2835 "MS UI Gothic","MS Serif",
2836 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2839 /* Chinese Simplified */
2840 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2841 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2842 "SimSun", "NSimSun",
2843 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2847 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2848 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2850 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2853 /* Chinese Traditional */
2854 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2855 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2856 "PMingLiU", "MingLiU",
2857 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2862 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2864 return ( ansi_cp
== 932 /* CP932 for Japanese */
2865 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2866 || ansi_cp
== 949 /* CP949 for Korean */
2867 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2870 static inline HKEY
create_fonts_NT_registry_key(void)
2874 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2875 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2879 static inline HKEY
create_fonts_9x_registry_key(void)
2883 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2884 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2888 static inline HKEY
create_config_fonts_registry_key(void)
2892 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2893 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2897 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2899 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2900 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2901 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2902 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2905 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2908 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2910 RegDeleteValueA(hkey
, name
);
2913 static void update_font_info(void)
2915 char buf
[40], cpbuf
[40];
2918 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2921 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2924 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2925 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2926 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2927 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2928 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2930 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2931 if (is_dbcs_ansi_cp(ansi_cp
))
2932 use_default_fallback
= TRUE
;
2935 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2937 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2942 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2944 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2946 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2949 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2953 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2954 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2956 hkey
= create_config_fonts_registry_key();
2957 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2958 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2959 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2962 hkey
= create_fonts_NT_registry_key();
2963 add_font_list(hkey
, &nls_update_font_list
[i
]);
2966 hkey
= create_fonts_9x_registry_key();
2967 add_font_list(hkey
, &nls_update_font_list
[i
]);
2970 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2972 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2973 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2974 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2975 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2977 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2978 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2979 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2980 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2981 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2982 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2983 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2984 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2986 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2987 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2988 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2996 /* Delete the FontSubstitutes from other locales */
2997 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2999 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3000 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3001 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3007 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3010 static BOOL
init_freetype(void)
3012 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3015 "Wine cannot find the FreeType font library. To enable Wine to\n"
3016 "use TrueType fonts please install a version of FreeType greater than\n"
3017 "or equal to 2.0.5.\n"
3018 "http://www.freetype.org\n");
3022 #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;}
3024 LOAD_FUNCPTR(FT_Done_Face
)
3025 LOAD_FUNCPTR(FT_Get_Char_Index
)
3026 LOAD_FUNCPTR(FT_Get_First_Char
)
3027 LOAD_FUNCPTR(FT_Get_Module
)
3028 LOAD_FUNCPTR(FT_Get_Next_Char
)
3029 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3030 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3031 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3032 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3033 LOAD_FUNCPTR(FT_Init_FreeType
)
3034 LOAD_FUNCPTR(FT_Library_Version
)
3035 LOAD_FUNCPTR(FT_Load_Glyph
)
3036 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3037 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3038 #ifndef FT_MULFIX_INLINED
3039 LOAD_FUNCPTR(FT_MulFix
)
3041 LOAD_FUNCPTR(FT_New_Face
)
3042 LOAD_FUNCPTR(FT_New_Memory_Face
)
3043 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3044 LOAD_FUNCPTR(FT_Outline_Transform
)
3045 LOAD_FUNCPTR(FT_Outline_Translate
)
3046 LOAD_FUNCPTR(FT_Render_Glyph
)
3047 LOAD_FUNCPTR(FT_Select_Charmap
)
3048 LOAD_FUNCPTR(FT_Set_Charmap
)
3049 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3050 LOAD_FUNCPTR(FT_Vector_Transform
)
3051 LOAD_FUNCPTR(FT_Vector_Unit
)
3053 /* Don't warn if these ones are missing */
3054 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3055 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3056 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3059 if(pFT_Init_FreeType(&library
) != 0) {
3060 ERR("Can't init FreeType library\n");
3061 wine_dlclose(ft_handle
, NULL
, 0);
3065 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3067 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3068 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3069 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3070 ((FT_Version
.patch
) & 0x0000ff);
3072 font_driver
= &freetype_funcs
;
3077 "Wine cannot find certain functions that it needs inside the FreeType\n"
3078 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3079 "FreeType to at least version 2.1.4.\n"
3080 "http://www.freetype.org\n");
3081 wine_dlclose(ft_handle
, NULL
, 0);
3086 static void init_font_list(void)
3088 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3089 static const WCHAR pathW
[] = {'P','a','t','h',0};
3091 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3092 WCHAR windowsdir
[MAX_PATH
];
3095 const char *data_dir
;
3097 delete_external_font_keys();
3099 /* load the system bitmap fonts */
3100 load_system_fonts();
3102 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3103 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3104 strcatW(windowsdir
, fontsW
);
3105 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3107 ReadFontDir(unixname
, FALSE
);
3108 HeapFree(GetProcessHeap(), 0, unixname
);
3111 /* load the system truetype fonts */
3112 data_dir
= wine_get_data_dir();
3113 if (!data_dir
) data_dir
= wine_get_build_dir();
3114 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3116 strcpy(unixname
, data_dir
);
3117 strcat(unixname
, "/fonts/");
3118 ReadFontDir(unixname
, TRUE
);
3119 HeapFree(GetProcessHeap(), 0, unixname
);
3122 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3123 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3124 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3126 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3127 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3128 &hkey
) == ERROR_SUCCESS
)
3130 LPWSTR data
, valueW
;
3131 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3132 &valuelen
, &datalen
, NULL
, NULL
);
3134 valuelen
++; /* returned value doesn't include room for '\0' */
3135 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3136 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3139 dlen
= datalen
* sizeof(WCHAR
);
3141 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3142 &dlen
) == ERROR_SUCCESS
)
3144 if(data
[0] && (data
[1] == ':'))
3146 if((unixname
= wine_get_unix_file_name(data
)))
3148 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3149 HeapFree(GetProcessHeap(), 0, unixname
);
3152 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3154 WCHAR pathW
[MAX_PATH
];
3155 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3158 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3159 if((unixname
= wine_get_unix_file_name(pathW
)))
3161 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3162 HeapFree(GetProcessHeap(), 0, unixname
);
3165 load_font_from_data_dir(data
);
3167 /* reset dlen and vlen */
3172 HeapFree(GetProcessHeap(), 0, data
);
3173 HeapFree(GetProcessHeap(), 0, valueW
);
3177 load_fontconfig_fonts();
3179 /* then look in any directories that we've specified in the config file */
3180 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3181 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3187 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3189 len
+= sizeof(WCHAR
);
3190 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3191 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3193 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3194 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3195 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3196 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3200 LPSTR next
= strchr( ptr
, ':' );
3201 if (next
) *next
++ = 0;
3202 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3203 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3205 strcpy( unixname
, home
);
3206 strcat( unixname
, ptr
+ 1 );
3207 ReadFontDir( unixname
, TRUE
);
3208 HeapFree( GetProcessHeap(), 0, unixname
);
3211 ReadFontDir( ptr
, TRUE
);
3214 HeapFree( GetProcessHeap(), 0, valueA
);
3216 HeapFree( GetProcessHeap(), 0, valueW
);
3222 /* Mac default font locations. */
3223 ReadFontDir( "/Library/Fonts", TRUE
);
3224 ReadFontDir( "/Network/Library/Fonts", TRUE
);
3225 ReadFontDir( "/System/Library/Fonts", TRUE
);
3226 if ((home
= getenv( "HOME" )))
3228 unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(home
)+15 );
3229 strcpy( unixname
, home
);
3230 strcat( unixname
, "/Library/Fonts" );
3231 ReadFontDir( unixname
, TRUE
);
3232 HeapFree( GetProcessHeap(), 0, unixname
);
3237 static BOOL
move_to_front(const WCHAR
*name
)
3239 Family
*family
, *cursor2
;
3240 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3242 if(!strcmpiW(family
->FamilyName
, name
))
3244 list_remove(&family
->entry
);
3245 list_add_head(&font_list
, &family
->entry
);
3252 static BOOL
set_default(const WCHAR
**name_list
)
3256 if (move_to_front(*name_list
)) return TRUE
;
3263 static void reorder_font_list(void)
3265 set_default( default_serif_list
);
3266 set_default( default_fixed_list
);
3267 set_default( default_sans_list
);
3270 /*************************************************************
3273 * Initialize FreeType library and create a list of available faces
3275 BOOL
WineEngInit(void)
3277 HKEY hkey_font_cache
;
3281 /* update locale dependent font info in registry */
3284 if(!init_freetype()) return FALSE
;
3286 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3288 ERR("Failed to create font mutex\n");
3291 WaitForSingleObject(font_mutex
, INFINITE
);
3293 create_font_cache_key(&hkey_font_cache
, &disposition
);
3295 if(disposition
== REG_CREATED_NEW_KEY
)
3298 load_font_list_from_cache(hkey_font_cache
);
3300 RegCloseKey(hkey_font_cache
);
3302 reorder_font_list();
3309 if(disposition
== REG_CREATED_NEW_KEY
)
3310 update_reg_entries();
3312 init_system_links();
3314 ReleaseMutex(font_mutex
);
3319 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3322 TT_HoriHeader
*pHori
;
3326 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3327 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3329 if(height
== 0) height
= 16;
3331 /* Calc. height of EM square:
3333 * For +ve lfHeight we have
3334 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3335 * Re-arranging gives:
3336 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3338 * For -ve lfHeight we have
3340 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3341 * with il = winAscent + winDescent - units_per_em]
3346 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3347 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3348 pHori
->Ascender
- pHori
->Descender
);
3350 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3351 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3359 static struct font_mapping
*map_font_file( const char *name
)
3361 struct font_mapping
*mapping
;
3365 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3366 if (fstat( fd
, &st
) == -1) goto error
;
3368 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3370 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3372 mapping
->refcount
++;
3377 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3380 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3383 if (mapping
->data
== MAP_FAILED
)
3385 HeapFree( GetProcessHeap(), 0, mapping
);
3388 mapping
->refcount
= 1;
3389 mapping
->dev
= st
.st_dev
;
3390 mapping
->ino
= st
.st_ino
;
3391 mapping
->size
= st
.st_size
;
3392 list_add_tail( &mappings_list
, &mapping
->entry
);
3400 static void unmap_font_file( struct font_mapping
*mapping
)
3402 if (!--mapping
->refcount
)
3404 list_remove( &mapping
->entry
);
3405 munmap( mapping
->data
, mapping
->size
);
3406 HeapFree( GetProcessHeap(), 0, mapping
);
3410 static LONG
load_VDMX(GdiFont
*, LONG
);
3412 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3419 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3423 if (!(font
->mapping
= map_font_file( face
->file
)))
3425 WARN("failed to map %s\n", debugstr_a(face
->file
));
3428 data_ptr
= font
->mapping
->data
;
3429 data_size
= font
->mapping
->size
;
3433 data_ptr
= face
->font_data_ptr
;
3434 data_size
= face
->font_data_size
;
3437 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3439 ERR("FT_New_Face rets %d\n", err
);
3443 /* set it here, as load_VDMX needs it */
3444 font
->ft_face
= ft_face
;
3446 if(FT_IS_SCALABLE(ft_face
)) {
3447 /* load the VDMX table if we have one */
3448 font
->ppem
= load_VDMX(font
, height
);
3450 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3451 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3453 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3454 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3456 font
->ppem
= height
;
3457 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3458 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3464 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3466 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3467 a single face with the requested charset. The idea is to check if
3468 the selected font supports the current ANSI codepage, if it does
3469 return the corresponding charset, else return the first charset */
3472 int acp
= GetACP(), i
;
3476 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3478 const SYSTEM_LINKS
*font_link
;
3480 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
3481 return csi
.ciCharset
;
3483 font_link
= find_font_link(family_name
);
3484 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
3485 return csi
.ciCharset
;
3488 for(i
= 0; i
< 32; i
++) {
3490 if(face
->fs
.fsCsb
[0] & fs0
) {
3491 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3493 return csi
.ciCharset
;
3496 FIXME("TCI failing on %x\n", fs0
);
3500 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3501 face
->fs
.fsCsb
[0], face
->file
);
3503 return DEFAULT_CHARSET
;
3506 static GdiFont
*alloc_font(void)
3508 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3510 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3511 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3513 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3514 ret
->total_kern_pairs
= (DWORD
)-1;
3515 ret
->kern_pairs
= NULL
;
3516 list_init(&ret
->hfontlist
);
3517 list_init(&ret
->child_fonts
);
3521 static void free_font(GdiFont
*font
)
3523 struct list
*cursor
, *cursor2
;
3526 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3528 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3529 list_remove(cursor
);
3531 free_font(child
->font
);
3532 HeapFree(GetProcessHeap(), 0, child
);
3535 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3537 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3538 DeleteObject(hfontlist
->hfont
);
3539 list_remove(&hfontlist
->entry
);
3540 HeapFree(GetProcessHeap(), 0, hfontlist
);
3543 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3544 if (font
->mapping
) unmap_font_file( font
->mapping
);
3545 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3546 HeapFree(GetProcessHeap(), 0, font
->potm
);
3547 HeapFree(GetProcessHeap(), 0, font
->name
);
3548 for (i
= 0; i
< font
->gmsize
; i
++)
3549 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3550 HeapFree(GetProcessHeap(), 0, font
->gm
);
3551 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3552 HeapFree(GetProcessHeap(), 0, font
);
3556 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3558 FT_Face ft_face
= font
->ft_face
;
3562 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3569 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3571 /* make sure value of len is the value freetype says it needs */
3574 FT_ULong needed
= 0;
3575 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3576 if( !err
&& needed
< len
) len
= needed
;
3578 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3581 TRACE("Can't find table %c%c%c%c\n",
3582 /* bytes were reversed */
3583 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3584 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3590 /*************************************************************
3593 * load the vdmx entry for the specified height
3596 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3597 ( ( (FT_ULong)_x4 << 24 ) | \
3598 ( (FT_ULong)_x3 << 16 ) | \
3599 ( (FT_ULong)_x2 << 8 ) | \
3602 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3617 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3621 BYTE devXRatio
, devYRatio
;
3622 USHORT numRecs
, numRatios
;
3623 DWORD result
, offset
= -1;
3627 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3629 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3632 /* FIXME: need the real device aspect ratio */
3636 numRecs
= GET_BE_WORD(hdr
[1]);
3637 numRatios
= GET_BE_WORD(hdr
[2]);
3639 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3640 for(i
= 0; i
< numRatios
; i
++) {
3643 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3644 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3647 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3649 if((ratio
.xRatio
== 0 &&
3650 ratio
.yStartRatio
== 0 &&
3651 ratio
.yEndRatio
== 0) ||
3652 (devXRatio
== ratio
.xRatio
&&
3653 devYRatio
>= ratio
.yStartRatio
&&
3654 devYRatio
<= ratio
.yEndRatio
))
3656 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3657 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3658 offset
= GET_BE_WORD(tmp
);
3664 FIXME("No suitable ratio found\n");
3668 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3670 BYTE startsz
, endsz
;
3673 recs
= GET_BE_WORD(group
.recs
);
3674 startsz
= group
.startsz
;
3675 endsz
= group
.endsz
;
3677 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3679 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3680 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3681 if(result
== GDI_ERROR
) {
3682 FIXME("Failed to retrieve vTable\n");
3687 for(i
= 0; i
< recs
; i
++) {
3688 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3689 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3690 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3692 if(yMax
+ -yMin
== height
) {
3695 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3698 if(yMax
+ -yMin
> height
) {
3701 goto end
; /* failed */
3703 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3704 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3705 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3706 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3712 TRACE("ppem not found for height %d\n", height
);
3716 HeapFree(GetProcessHeap(), 0, vTable
);
3722 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3724 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3725 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3726 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3727 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3728 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3731 static void calc_hash(FONT_DESC
*pfd
)
3733 DWORD hash
= 0, *ptr
, two_chars
;
3737 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3739 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3741 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3743 pwc
= (WCHAR
*)&two_chars
;
3745 *pwc
= toupperW(*pwc
);
3747 *pwc
= toupperW(*pwc
);
3751 hash
^= !pfd
->can_use_bitmap
;
3756 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3761 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3765 fd
.can_use_bitmap
= can_use_bitmap
;
3768 /* try the child list */
3769 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3770 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3771 if(!fontcmp(ret
, &fd
)) {
3772 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3773 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3774 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3775 if(hflist
->hfont
== hfont
)
3781 /* try the in-use list */
3782 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3783 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3784 if(!fontcmp(ret
, &fd
)) {
3785 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3786 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3787 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3788 if(hflist
->hfont
== hfont
)
3791 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3792 hflist
->hfont
= hfont
;
3793 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3798 /* then the unused list */
3799 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3800 while(font_elem_ptr
) {
3801 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3802 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3803 if(!fontcmp(ret
, &fd
)) {
3804 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3805 assert(list_empty(&ret
->hfontlist
));
3806 TRACE("Found %p in unused list\n", ret
);
3807 list_remove(&ret
->entry
);
3808 list_add_head(&gdi_font_list
, &ret
->entry
);
3809 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3810 hflist
->hfont
= hfont
;
3811 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3818 static void add_to_cache(GdiFont
*font
)
3820 static DWORD cache_num
= 1;
3822 font
->cache_num
= cache_num
++;
3823 list_add_head(&gdi_font_list
, &font
->entry
);
3826 /*************************************************************
3827 * create_child_font_list
3829 static BOOL
create_child_font_list(GdiFont
*font
)
3832 SYSTEM_LINKS
*font_link
;
3833 CHILD_FONT
*font_link_entry
, *new_child
;
3837 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3838 font_name
= psub
? psub
->to
.name
: font
->name
;
3839 font_link
= find_font_link(font_name
);
3840 if (font_link
!= NULL
)
3842 TRACE("found entry in system list\n");
3843 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3845 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3846 new_child
->face
= font_link_entry
->face
;
3847 new_child
->font
= NULL
;
3848 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3849 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3854 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3855 * Sans Serif. This is how asian windows get default fallbacks for fonts
3857 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3858 font
->charset
!= OEM_CHARSET
&&
3859 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3861 font_link
= find_font_link(szDefaultFallbackLink
);
3862 if (font_link
!= NULL
)
3864 TRACE("found entry in default fallback list\n");
3865 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3867 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3868 new_child
->face
= font_link_entry
->face
;
3869 new_child
->font
= NULL
;
3870 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3871 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3880 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3882 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3884 if (pFT_Set_Charmap
)
3887 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3889 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3891 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3893 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3895 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3896 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3898 switch (ft_face
->charmaps
[i
]->platform_id
)
3901 cmap_def
= ft_face
->charmaps
[i
];
3903 case 0: /* Apple Unicode */
3904 cmap0
= ft_face
->charmaps
[i
];
3906 case 1: /* Macintosh */
3907 cmap1
= ft_face
->charmaps
[i
];
3910 cmap2
= ft_face
->charmaps
[i
];
3912 case 3: /* Microsoft */
3913 cmap3
= ft_face
->charmaps
[i
];
3918 if (cmap3
) /* prefer Microsoft cmap table */
3919 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3921 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3923 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3925 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3927 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3929 return ft_err
== FT_Err_Ok
;
3932 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3936 /*************************************************************
3939 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
3940 LPCWSTR output
, const DEVMODEW
*devmode
)
3942 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
3944 if (!physdev
) return FALSE
;
3945 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
3950 /*************************************************************
3953 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
3955 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3956 HeapFree( GetProcessHeap(), 0, physdev
);
3961 /*************************************************************
3962 * freetype_SelectFont
3964 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
3966 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3968 Face
*face
, *best
, *best_bitmap
;
3969 Family
*family
, *last_resort_family
;
3970 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
3971 INT height
, width
= 0;
3972 unsigned int score
= 0, new_score
;
3973 signed int diff
= 0, newdiff
;
3974 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
3979 FontSubst
*psub
= NULL
;
3980 DC
*dc
= get_dc_ptr( dev
->hdc
);
3981 const SYSTEM_LINKS
*font_link
;
3983 if (!hfont
) /* notification that the font has been changed by another driver */
3986 physdev
->font
= NULL
;
3987 release_dc_ptr( dc
);
3991 GetObjectW( hfont
, sizeof(lf
), &lf
);
3992 lf
.lfWidth
= abs(lf
.lfWidth
);
3994 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
3996 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3997 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3998 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4001 if(dc
->GraphicsMode
== GM_ADVANCED
)
4003 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4004 /* Try to avoid not necessary glyph transformations */
4005 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4007 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4008 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4009 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4014 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4015 font scaling abilities. */
4016 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4017 dcmat
.eM21
= dcmat
.eM12
= 0;
4018 if (dc
->vport2WorldValid
)
4020 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4021 lf
.lfOrientation
= -lf
.lfOrientation
;
4022 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4023 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4027 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4028 dcmat
.eM21
, dcmat
.eM22
);
4031 EnterCriticalSection( &freetype_cs
);
4033 /* check the cache first */
4034 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4035 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4039 if(list_empty(&font_list
)) /* No fonts installed */
4041 TRACE("No fonts installed\n");
4045 TRACE("not in cache\n");
4048 ret
->font_desc
.matrix
= dcmat
;
4049 ret
->font_desc
.lf
= lf
;
4050 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4051 calc_hash(&ret
->font_desc
);
4052 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4053 hflist
->hfont
= hfont
;
4054 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4056 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4057 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4058 original value lfCharSet. Note this is a special case for
4059 Symbol and doesn't happen at least for "Wingdings*" */
4061 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4062 lf
.lfCharSet
= SYMBOL_CHARSET
;
4064 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4065 switch(lf
.lfCharSet
) {
4066 case DEFAULT_CHARSET
:
4067 csi
.fs
.fsCsb
[0] = 0;
4070 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4071 csi
.fs
.fsCsb
[0] = 0;
4077 if(lf
.lfFaceName
[0] != '\0') {
4078 CHILD_FONT
*font_link_entry
;
4079 LPWSTR FaceName
= lf
.lfFaceName
;
4081 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4084 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4085 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4086 if (psub
->to
.charset
!= -1)
4087 lf
.lfCharSet
= psub
->to
.charset
;
4090 /* We want a match on name and charset or just name if
4091 charset was DEFAULT_CHARSET. If the latter then
4092 we fixup the returned charset later in get_nearest_charset
4093 where we'll either use the charset of the current ansi codepage
4094 or if that's unavailable the first charset that the font supports.
4096 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4097 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4098 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4099 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4101 font_link
= find_font_link(family
->FamilyName
);
4102 face_list
= get_face_list_from_family(family
);
4103 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4104 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4105 if (!(face
->scalable
|| can_use_bitmap
))
4107 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4109 if (font_link
!= NULL
&&
4110 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4112 if (!csi
.fs
.fsCsb
[0])
4118 /* Search by full face name. */
4119 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4120 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4121 face_list
= get_face_list_from_family(family
);
4122 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4123 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4124 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4125 (face
->scalable
|| can_use_bitmap
))
4127 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4129 font_link
= find_font_link(family
->FamilyName
);
4130 if (font_link
!= NULL
&&
4131 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4138 * Try check the SystemLink list first for a replacement font.
4139 * We may find good replacements there.
4141 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4143 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4144 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4146 TRACE("found entry in system list\n");
4147 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4149 const SYSTEM_LINKS
*links
;
4151 face
= font_link_entry
->face
;
4152 if (!(face
->scalable
|| can_use_bitmap
))
4154 family
= face
->family
;
4155 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4157 links
= find_font_link(family
->FamilyName
);
4158 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4165 psub
= NULL
; /* substitution is no more relevant */
4167 /* If requested charset was DEFAULT_CHARSET then try using charset
4168 corresponding to the current ansi codepage */
4169 if (!csi
.fs
.fsCsb
[0])
4172 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4173 FIXME("TCI failed on codepage %d\n", acp
);
4174 csi
.fs
.fsCsb
[0] = 0;
4176 lf
.lfCharSet
= csi
.ciCharset
;
4179 want_vertical
= (lf
.lfFaceName
[0] == '@');
4181 /* Face families are in the top 4 bits of lfPitchAndFamily,
4182 so mask with 0xF0 before testing */
4184 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4185 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4186 strcpyW(lf
.lfFaceName
, defFixed
);
4187 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4188 strcpyW(lf
.lfFaceName
, defSerif
);
4189 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4190 strcpyW(lf
.lfFaceName
, defSans
);
4192 strcpyW(lf
.lfFaceName
, defSans
);
4193 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4194 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4195 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4196 font_link
= find_font_link(family
->FamilyName
);
4197 face_list
= get_face_list_from_family(family
);
4198 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4199 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4200 if (!(face
->scalable
|| can_use_bitmap
))
4202 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4204 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4210 last_resort_family
= NULL
;
4211 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4212 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4213 font_link
= find_font_link(family
->FamilyName
);
4214 face_list
= get_face_list_from_family(family
);
4215 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4216 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4217 if(face
->vertical
== want_vertical
&&
4218 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4219 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4222 if(can_use_bitmap
&& !last_resort_family
)
4223 last_resort_family
= family
;
4228 if(last_resort_family
) {
4229 family
= last_resort_family
;
4230 csi
.fs
.fsCsb
[0] = 0;
4234 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4235 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4236 face_list
= get_face_list_from_family(family
);
4237 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4238 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4239 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4240 csi
.fs
.fsCsb
[0] = 0;
4241 WARN("just using first face for now\n");
4244 if(can_use_bitmap
&& !last_resort_family
)
4245 last_resort_family
= family
;
4248 if(!last_resort_family
) {
4249 FIXME("can't find a single appropriate font - bailing\n");
4255 WARN("could only find a bitmap font - this will probably look awful!\n");
4256 family
= last_resort_family
;
4257 csi
.fs
.fsCsb
[0] = 0;
4260 it
= lf
.lfItalic
? 1 : 0;
4261 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4263 height
= lf
.lfHeight
;
4265 face
= best
= best_bitmap
= NULL
;
4266 font_link
= find_font_link(family
->FamilyName
);
4267 face_list
= get_face_list_from_family(family
);
4268 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4270 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4271 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4276 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4277 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4278 new_score
= (italic
^ it
) + (bold
^ bd
);
4279 if(!best
|| new_score
<= score
)
4281 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4282 italic
, bold
, it
, bd
);
4285 if(best
->scalable
&& score
== 0) break;
4289 newdiff
= height
- (signed int)(best
->size
.height
);
4291 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4292 if(!best_bitmap
|| new_score
< score
||
4293 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4295 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4298 if(score
== 0 && diff
== 0) break;
4305 face
= best
->scalable
? best
: best_bitmap
;
4306 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4307 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4310 height
= lf
.lfHeight
;
4314 if(csi
.fs
.fsCsb
[0]) {
4315 ret
->charset
= lf
.lfCharSet
;
4316 ret
->codepage
= csi
.ciACP
;
4319 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4321 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4322 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4324 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4326 if(!face
->scalable
) {
4327 /* Windows uses integer scaling factors for bitmap fonts */
4328 INT scale
, scaled_height
;
4329 GdiFont
*cachedfont
;
4331 /* FIXME: rotation of bitmap fonts is ignored */
4332 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4334 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4335 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4336 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4337 /* As we changed the matrix, we need to search the cache for the font again,
4338 * otherwise we might explode the cache. */
4339 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4340 TRACE("Found cached font after non-scalable matrix rescale!\n");
4345 calc_hash(&ret
->font_desc
);
4347 if (height
!= 0) height
= diff
;
4348 height
+= face
->size
.height
;
4350 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4351 scaled_height
= scale
* face
->size
.height
;
4352 /* Only jump to the next height if the difference <= 25% original height */
4353 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4354 /* The jump between unscaled and doubled is delayed by 1 */
4355 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4356 ret
->scale_y
= scale
;
4358 width
= face
->size
.x_ppem
>> 6;
4359 height
= face
->size
.y_ppem
>> 6;
4363 TRACE("font scale y: %f\n", ret
->scale_y
);
4365 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4374 ret
->ntmFlags
= face
->ntmFlags
;
4376 if (ret
->charset
== SYMBOL_CHARSET
&&
4377 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4380 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4384 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4387 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4388 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4389 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4390 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4391 create_child_font_list(ret
);
4393 if (face
->vertical
) /* We need to try to load the GSUB table */
4395 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4396 if (length
!= GDI_ERROR
)
4398 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4399 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4400 TRACE("Loaded GSUB table of %i bytes\n",length
);
4404 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4411 physdev
->font
= ret
;
4413 LeaveCriticalSection( &freetype_cs
);
4414 release_dc_ptr( dc
);
4415 return ret
? hfont
: 0;
4418 static void dump_gdi_font_list(void)
4421 struct list
*elem_ptr
;
4423 TRACE("---------- gdiFont Cache ----------\n");
4424 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4425 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4426 TRACE("gdiFont=%p %s %d\n",
4427 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4430 TRACE("---------- Unused gdiFont Cache ----------\n");
4431 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4432 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4433 TRACE("gdiFont=%p %s %d\n",
4434 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4437 TRACE("---------- Child gdiFont Cache ----------\n");
4438 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4439 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4440 TRACE("gdiFont=%p %s %d\n",
4441 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4445 /*************************************************************
4446 * WineEngDestroyFontInstance
4448 * free the gdiFont associated with this handle
4451 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4456 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4460 EnterCriticalSection( &freetype_cs
);
4462 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4464 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4465 while(hfontlist_elem_ptr
) {
4466 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4467 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4468 if(hflist
->hfont
== handle
) {
4469 TRACE("removing child font %p from child list\n", gdiFont
);
4470 list_remove(&gdiFont
->entry
);
4471 LeaveCriticalSection( &freetype_cs
);
4477 TRACE("destroying hfont=%p\n", handle
);
4479 dump_gdi_font_list();
4481 font_elem_ptr
= list_head(&gdi_font_list
);
4482 while(font_elem_ptr
) {
4483 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4484 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4486 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4487 while(hfontlist_elem_ptr
) {
4488 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4489 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4490 if(hflist
->hfont
== handle
) {
4491 list_remove(&hflist
->entry
);
4492 HeapFree(GetProcessHeap(), 0, hflist
);
4496 if(list_empty(&gdiFont
->hfontlist
)) {
4497 TRACE("Moving to Unused list\n");
4498 list_remove(&gdiFont
->entry
);
4499 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4504 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4505 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4506 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4507 while(font_elem_ptr
) {
4508 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4509 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4510 TRACE("freeing %p\n", gdiFont
);
4511 list_remove(&gdiFont
->entry
);
4514 LeaveCriticalSection( &freetype_cs
);
4518 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4525 id
+= IDS_FIRST_SCRIPT
;
4526 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4527 if (!rsrc
) return 0;
4528 hMem
= LoadResource( gdi32_module
, rsrc
);
4529 if (!hMem
) return 0;
4531 p
= LockResource( hMem
);
4533 while (id
--) p
+= *p
+ 1;
4535 i
= min(LF_FACESIZE
- 1, *p
);
4536 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4542 /***************************************************
4543 * create_enum_charset_list
4545 * This function creates charset enumeration list because in DEFAULT_CHARSET
4546 * case, the ANSI codepage's charset takes precedence over other charsets.
4547 * This function works as a filter other than DEFAULT_CHARSET case.
4549 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4554 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4555 csi
.fs
.fsCsb
[0] != 0) {
4556 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4557 list
->element
[n
].charset
= csi
.ciCharset
;
4558 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4561 else { /* charset is DEFAULT_CHARSET or invalid. */
4564 /* Set the current codepage's charset as the first element. */
4566 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4567 csi
.fs
.fsCsb
[0] != 0) {
4568 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4569 list
->element
[n
].charset
= csi
.ciCharset
;
4570 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4574 /* Fill out left elements. */
4575 for (i
= 0; i
< 32; i
++) {
4577 fs
.fsCsb
[0] = 1L << i
;
4579 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4580 continue; /* skip, already added. */
4581 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4582 continue; /* skip, this is an invalid fsCsb bit. */
4584 list
->element
[n
].mask
= fs
.fsCsb
[0];
4585 list
->element
[n
].charset
= csi
.ciCharset
;
4586 load_script_name( i
, list
->element
[n
].name
);
4595 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4596 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4601 if (face
->cached_enum_data
)
4604 *pelf
= face
->cached_enum_data
->elf
;
4605 *pntm
= face
->cached_enum_data
->ntm
;
4606 *ptype
= face
->cached_enum_data
->type
;
4610 font
= alloc_font();
4612 if(face
->scalable
) {
4613 height
= -2048; /* 2048 is the most common em size */
4616 height
= face
->size
.y_ppem
>> 6;
4617 width
= face
->size
.x_ppem
>> 6;
4619 font
->scale_y
= 1.0;
4621 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4627 font
->name
= strdupW(face
->family
->FamilyName
);
4628 font
->ntmFlags
= face
->ntmFlags
;
4630 if (get_outline_text_metrics(font
))
4632 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4634 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4636 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4637 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4639 lstrcpynW(pelf
->elfFullName
,
4640 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4642 lstrcpynW(pelf
->elfStyle
,
4643 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4648 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4650 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4652 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4654 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4656 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4657 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4660 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4661 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4662 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4663 pntm
->ntmFontSig
= face
->fs
;
4665 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4667 pelf
->elfLogFont
.lfEscapement
= 0;
4668 pelf
->elfLogFont
.lfOrientation
= 0;
4669 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4670 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4671 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4672 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4673 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4674 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4675 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4676 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4677 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4678 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4679 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4682 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4683 *ptype
|= TRUETYPE_FONTTYPE
;
4684 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4685 *ptype
|= DEVICE_FONTTYPE
;
4686 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4687 *ptype
|= RASTER_FONTTYPE
;
4689 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4690 if (face
->cached_enum_data
)
4692 face
->cached_enum_data
->elf
= *pelf
;
4693 face
->cached_enum_data
->ntm
= *pntm
;
4694 face
->cached_enum_data
->type
= *ptype
;
4700 static void create_full_name(WCHAR
*full_name
, const WCHAR
*family_name
, const WCHAR
*style_name
)
4702 static const WCHAR spaceW
[] = { ' ', 0 };
4704 strcpyW(full_name
, family_name
);
4705 strcatW(full_name
, spaceW
);
4706 strcatW(full_name
, style_name
);
4709 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4711 const struct list
*face_list
, *face_elem_ptr
;
4713 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4715 face_list
= get_face_list_from_family(family
);
4716 LIST_FOR_EACH(face_elem_ptr
, face_list
)
4718 WCHAR full_family_name
[LF_FULLFACESIZE
];
4719 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4721 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4723 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4724 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4728 create_full_name(full_family_name
, family
->FamilyName
, face
->StyleName
);
4729 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4735 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
4737 WCHAR full_family_name
[LF_FULLFACESIZE
];
4739 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
4741 if (strlenW(family_name
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4743 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4744 debugstr_w(family_name
), debugstr_w(face
->StyleName
));
4748 create_full_name(full_family_name
, family_name
, face
->StyleName
);
4749 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4752 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
4753 FONTENUMPROCW proc
, LPARAM lparam
)
4756 NEWTEXTMETRICEXW ntm
;
4760 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4761 for(i
= 0; i
< list
->total
; i
++) {
4762 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4763 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4764 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4765 i
= list
->total
; /* break out of loop after enumeration */
4766 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4769 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4770 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4771 if (!elf
.elfScript
[0])
4772 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4774 /* Font Replacement */
4775 if (family
!= face
->family
)
4777 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
4778 create_full_name(elf
.elfFullName
, family
->FamilyName
, face
->StyleName
);
4780 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4781 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4782 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4783 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4784 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4785 ntm
.ntmTm
.ntmFlags
);
4786 /* release section before callback (FIXME) */
4787 LeaveCriticalSection( &freetype_cs
);
4788 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4789 EnterCriticalSection( &freetype_cs
);
4794 /*************************************************************
4795 * freetype_EnumFonts
4797 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4801 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4803 struct enum_charset_list enum_charsets
;
4807 lf
.lfCharSet
= DEFAULT_CHARSET
;
4808 lf
.lfPitchAndFamily
= 0;
4809 lf
.lfFaceName
[0] = 0;
4813 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4815 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4818 EnterCriticalSection( &freetype_cs
);
4819 if(plf
->lfFaceName
[0]) {
4821 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4824 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4825 debugstr_w(psub
->to
.name
));
4827 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4831 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4832 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4833 if(family_matches(family
, plf
)) {
4834 face_list
= get_face_list_from_family(family
);
4835 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4836 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4837 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
4838 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4843 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4844 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4845 face_list
= get_face_list_from_family(family
);
4846 face_elem_ptr
= list_head(face_list
);
4847 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4848 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4851 LeaveCriticalSection( &freetype_cs
);
4855 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4857 pt
->x
.value
= vec
->x
>> 6;
4858 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4859 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4860 pt
->y
.value
= vec
->y
>> 6;
4861 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4862 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4866 /***************************************************
4867 * According to the MSDN documentation on WideCharToMultiByte,
4868 * certain codepages cannot set the default_used parameter.
4869 * This returns TRUE if the codepage can set that parameter, false else
4870 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4872 static BOOL
codepage_sets_default_used(UINT codepage
)
4886 * GSUB Table handling functions
4889 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4891 const GSUB_CoverageFormat1
* cf1
;
4895 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4897 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4899 TRACE("Coverage Format 1, %i glyphs\n",count
);
4900 for (i
= 0; i
< count
; i
++)
4901 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4905 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4907 const GSUB_CoverageFormat2
* cf2
;
4910 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4912 count
= GET_BE_WORD(cf2
->RangeCount
);
4913 TRACE("Coverage Format 2, %i ranges\n",count
);
4914 for (i
= 0; i
< count
; i
++)
4916 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4918 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4919 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4921 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4922 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4928 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4933 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4935 const GSUB_ScriptList
*script
;
4936 const GSUB_Script
*deflt
= NULL
;
4938 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4940 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4941 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4943 const GSUB_Script
*scr
;
4946 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4947 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4949 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4951 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4957 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4961 const GSUB_LangSys
*Lang
;
4963 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4965 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4967 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4968 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4970 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4973 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4976 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4982 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4985 const GSUB_FeatureList
*feature
;
4986 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4988 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4989 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4991 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4992 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4994 const GSUB_Feature
*feat
;
4995 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5002 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5006 const GSUB_LookupList
*lookup
;
5007 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5009 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5010 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5012 const GSUB_LookupTable
*look
;
5013 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5014 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5015 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5016 if (GET_BE_WORD(look
->LookupType
) != 1)
5017 FIXME("We only handle SubType 1\n");
5022 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5024 const GSUB_SingleSubstFormat1
*ssf1
;
5025 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5026 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5027 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5029 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5030 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5031 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5033 TRACE(" Glyph 0x%x ->",glyph
);
5034 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5035 TRACE(" 0x%x\n",glyph
);
5040 const GSUB_SingleSubstFormat2
*ssf2
;
5044 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5045 offset
= GET_BE_WORD(ssf1
->Coverage
);
5046 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5047 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5048 TRACE(" Coverage index %i\n",index
);
5051 TRACE(" Glyph is 0x%x ->",glyph
);
5052 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5053 TRACE("0x%x\n",glyph
);
5062 static const char* get_opentype_script(const GdiFont
*font
)
5065 * I am not sure if this is the correct way to generate our script tag
5068 switch (font
->charset
)
5070 case ANSI_CHARSET
: return "latn";
5071 case BALTIC_CHARSET
: return "latn"; /* ?? */
5072 case CHINESEBIG5_CHARSET
: return "hani";
5073 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5074 case GB2312_CHARSET
: return "hani";
5075 case GREEK_CHARSET
: return "grek";
5076 case HANGUL_CHARSET
: return "hang";
5077 case RUSSIAN_CHARSET
: return "cyrl";
5078 case SHIFTJIS_CHARSET
: return "kana";
5079 case TURKISH_CHARSET
: return "latn"; /* ?? */
5080 case VIETNAMESE_CHARSET
: return "latn";
5081 case JOHAB_CHARSET
: return "latn"; /* ?? */
5082 case ARABIC_CHARSET
: return "arab";
5083 case HEBREW_CHARSET
: return "hebr";
5084 case THAI_CHARSET
: return "thai";
5085 default: return "latn";
5089 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5091 const GSUB_Header
*header
;
5092 const GSUB_Script
*script
;
5093 const GSUB_LangSys
*language
;
5094 const GSUB_Feature
*feature
;
5096 if (!font
->GSUB_Table
)
5099 header
= font
->GSUB_Table
;
5101 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5104 TRACE("Script not found\n");
5107 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5110 TRACE("Language not found\n");
5113 feature
= GSUB_get_feature(header
, language
, "vrt2");
5115 feature
= GSUB_get_feature(header
, language
, "vert");
5118 TRACE("vrt2/vert feature not found\n");
5121 return GSUB_apply_feature(header
, feature
, glyph
);
5124 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5128 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5129 WCHAR wc
= (WCHAR
)glyph
;
5131 BOOL
*default_used_pointer
;
5134 default_used_pointer
= NULL
;
5135 default_used
= FALSE
;
5136 if (codepage_sets_default_used(font
->codepage
))
5137 default_used_pointer
= &default_used
;
5138 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5141 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5142 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5146 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5148 if (glyph
< 0x100) glyph
+= 0xf000;
5149 /* there is a number of old pre-Unicode "broken" TTFs, which
5150 do have symbols at U+00XX instead of U+f0XX */
5151 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5152 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5154 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5159 /*************************************************************
5160 * freetype_GetGlyphIndices
5162 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5164 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5167 BOOL got_default
= FALSE
;
5171 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5172 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5175 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5177 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5182 EnterCriticalSection( &freetype_cs
);
5184 for(i
= 0; i
< count
; i
++)
5186 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5191 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5193 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5194 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5199 get_text_metrics(physdev
->font
, &textm
);
5200 default_char
= textm
.tmDefaultChar
;
5204 pgi
[i
] = default_char
;
5207 LeaveCriticalSection( &freetype_cs
);
5211 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5213 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5214 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5217 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5219 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5220 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5223 static inline BYTE
get_max_level( UINT format
)
5227 case GGO_GRAY2_BITMAP
: return 4;
5228 case GGO_GRAY4_BITMAP
: return 16;
5229 case GGO_GRAY8_BITMAP
: return 64;
5234 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5236 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5237 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5240 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5241 FT_Face ft_face
= incoming_font
->ft_face
;
5242 GdiFont
*font
= incoming_font
;
5243 FT_UInt glyph_index
;
5244 DWORD width
, height
, pitch
, needed
= 0;
5245 FT_Bitmap ft_bitmap
;
5247 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5249 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5250 double widthRatio
= 1.0;
5251 FT_Matrix transMat
= identityMat
;
5252 FT_Matrix transMatUnrotated
;
5253 BOOL needsTransform
= FALSE
;
5254 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5255 UINT original_index
;
5257 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5258 buflen
, buf
, lpmat
);
5260 TRACE("font transform %f %f %f %f\n",
5261 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5262 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5264 if(format
& GGO_GLYPH_INDEX
) {
5265 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5266 original_index
= glyph
;
5267 format
&= ~GGO_GLYPH_INDEX
;
5269 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5270 ft_face
= font
->ft_face
;
5271 original_index
= glyph_index
;
5274 if(format
& GGO_UNHINTED
) {
5275 load_flags
|= FT_LOAD_NO_HINTING
;
5276 format
&= ~GGO_UNHINTED
;
5279 /* tategaki never appears to happen to lower glyph index */
5280 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5283 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5284 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5285 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5286 font
->gmsize
* sizeof(GM
*));
5288 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5289 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5291 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5292 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5293 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5294 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5295 return 1; /* FIXME */
5299 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5300 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5302 /* Scaling factor */
5307 get_text_metrics(font
, &tm
);
5309 widthRatio
= (double)font
->aveWidth
;
5310 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5313 widthRatio
= font
->scale_y
;
5315 /* Scaling transform */
5316 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5319 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5322 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5324 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5325 needsTransform
= TRUE
;
5328 /* Slant transform */
5329 if (font
->fake_italic
) {
5332 slantMat
.xx
= (1 << 16);
5333 slantMat
.xy
= ((1 << 16) >> 2);
5335 slantMat
.yy
= (1 << 16);
5336 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5337 needsTransform
= TRUE
;
5340 /* Rotation transform */
5341 transMatUnrotated
= transMat
;
5342 if(font
->orientation
&& !tategaki
) {
5343 FT_Matrix rotationMat
;
5345 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5346 pFT_Vector_Unit(&vecAngle
, angle
);
5347 rotationMat
.xx
= vecAngle
.x
;
5348 rotationMat
.xy
= -vecAngle
.y
;
5349 rotationMat
.yx
= -rotationMat
.xy
;
5350 rotationMat
.yy
= rotationMat
.xx
;
5352 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5353 needsTransform
= TRUE
;
5356 /* World transform */
5357 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5360 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5361 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5362 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5363 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5364 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5365 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5366 needsTransform
= TRUE
;
5369 /* Extra transformation specified by caller */
5370 if (!is_identity_MAT2(lpmat
))
5373 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5374 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5375 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5376 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5377 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5378 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5379 needsTransform
= TRUE
;
5382 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5383 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5384 format
== GGO_GRAY8_BITMAP
))
5386 load_flags
|= FT_LOAD_NO_BITMAP
;
5389 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5392 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5396 if(!needsTransform
) {
5397 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5398 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5399 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5401 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5402 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5403 ft_face
->glyph
->metrics
.height
) & -64;
5404 lpgm
->gmCellIncX
= adv
;
5405 lpgm
->gmCellIncY
= 0;
5412 for(xc
= 0; xc
< 2; xc
++) {
5413 for(yc
= 0; yc
< 2; yc
++) {
5414 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5415 xc
* ft_face
->glyph
->metrics
.width
);
5416 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5417 yc
* ft_face
->glyph
->metrics
.height
;
5418 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5419 pFT_Vector_Transform(&vec
, &transMat
);
5420 if(xc
== 0 && yc
== 0) {
5421 left
= right
= vec
.x
;
5422 top
= bottom
= vec
.y
;
5424 if(vec
.x
< left
) left
= vec
.x
;
5425 else if(vec
.x
> right
) right
= vec
.x
;
5426 if(vec
.y
< bottom
) bottom
= vec
.y
;
5427 else if(vec
.y
> top
) top
= vec
.y
;
5432 right
= (right
+ 63) & -64;
5433 bottom
= bottom
& -64;
5434 top
= (top
+ 63) & -64;
5436 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5437 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5439 pFT_Vector_Transform(&vec
, &transMat
);
5440 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5441 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5443 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5445 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5446 adv
= (vec
.x
+63) >> 6;
5450 bbx
= (right
- left
) >> 6;
5451 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5452 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5453 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5454 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5456 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5457 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5458 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5460 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5461 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5463 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5464 FONT_GM(font
,original_index
)->adv
= adv
;
5465 FONT_GM(font
,original_index
)->lsb
= lsb
;
5466 FONT_GM(font
,original_index
)->bbx
= bbx
;
5467 FONT_GM(font
,original_index
)->init
= TRUE
;
5470 if(format
== GGO_METRICS
)
5472 return 1; /* FIXME */
5475 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5476 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5478 TRACE("loaded a bitmap\n");
5484 width
= lpgm
->gmBlackBoxX
;
5485 height
= lpgm
->gmBlackBoxY
;
5486 pitch
= ((width
+ 31) >> 5) << 2;
5487 needed
= pitch
* height
;
5489 if(!buf
|| !buflen
) break;
5491 switch(ft_face
->glyph
->format
) {
5492 case ft_glyph_format_bitmap
:
5494 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5495 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5496 INT h
= ft_face
->glyph
->bitmap
.rows
;
5498 memcpy(dst
, src
, w
);
5499 src
+= ft_face
->glyph
->bitmap
.pitch
;
5505 case ft_glyph_format_outline
:
5506 ft_bitmap
.width
= width
;
5507 ft_bitmap
.rows
= height
;
5508 ft_bitmap
.pitch
= pitch
;
5509 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5510 ft_bitmap
.buffer
= buf
;
5513 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5515 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5517 /* Note: FreeType will only set 'black' bits for us. */
5518 memset(buf
, 0, needed
);
5519 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5523 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5528 case GGO_GRAY2_BITMAP
:
5529 case GGO_GRAY4_BITMAP
:
5530 case GGO_GRAY8_BITMAP
:
5531 case WINE_GGO_GRAY16_BITMAP
:
5533 unsigned int max_level
, row
, col
;
5536 width
= lpgm
->gmBlackBoxX
;
5537 height
= lpgm
->gmBlackBoxY
;
5538 pitch
= (width
+ 3) / 4 * 4;
5539 needed
= pitch
* height
;
5541 if(!buf
|| !buflen
) break;
5543 max_level
= get_max_level( format
);
5545 switch(ft_face
->glyph
->format
) {
5546 case ft_glyph_format_bitmap
:
5548 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5549 INT h
= ft_face
->glyph
->bitmap
.rows
;
5551 memset( buf
, 0, needed
);
5553 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5554 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5555 src
+= ft_face
->glyph
->bitmap
.pitch
;
5560 case ft_glyph_format_outline
:
5562 ft_bitmap
.width
= width
;
5563 ft_bitmap
.rows
= height
;
5564 ft_bitmap
.pitch
= pitch
;
5565 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5566 ft_bitmap
.buffer
= buf
;
5569 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5571 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5573 memset(ft_bitmap
.buffer
, 0, buflen
);
5575 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5577 if (max_level
!= 255)
5579 for (row
= 0, start
= buf
; row
< height
; row
++)
5581 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5582 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5590 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5596 case WINE_GGO_HRGB_BITMAP
:
5597 case WINE_GGO_HBGR_BITMAP
:
5598 case WINE_GGO_VRGB_BITMAP
:
5599 case WINE_GGO_VBGR_BITMAP
:
5600 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5602 switch (ft_face
->glyph
->format
)
5604 case FT_GLYPH_FORMAT_BITMAP
:
5609 width
= lpgm
->gmBlackBoxX
;
5610 height
= lpgm
->gmBlackBoxY
;
5612 needed
= pitch
* height
;
5614 if (!buf
|| !buflen
) break;
5616 memset(buf
, 0, buflen
);
5618 src
= ft_face
->glyph
->bitmap
.buffer
;
5619 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5621 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5624 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5626 if ( src
[x
/ 8] & masks
[x
% 8] )
5627 ((unsigned int *)dst
)[x
] = ~0u;
5636 case FT_GLYPH_FORMAT_OUTLINE
:
5640 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5641 INT x_shift
, y_shift
;
5643 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5644 FT_Render_Mode render_mode
=
5645 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5646 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5648 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5650 if ( render_mode
== FT_RENDER_MODE_LCD
)
5652 lpgm
->gmBlackBoxX
+= 2;
5653 lpgm
->gmptGlyphOrigin
.x
-= 1;
5657 lpgm
->gmBlackBoxY
+= 2;
5658 lpgm
->gmptGlyphOrigin
.y
+= 1;
5662 width
= lpgm
->gmBlackBoxX
;
5663 height
= lpgm
->gmBlackBoxY
;
5665 needed
= pitch
* height
;
5667 if (!buf
|| !buflen
) break;
5669 memset(buf
, 0, buflen
);
5671 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5673 if ( needsTransform
)
5674 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5676 if ( pFT_Library_SetLcdFilter
)
5677 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5678 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5680 src
= ft_face
->glyph
->bitmap
.buffer
;
5681 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5682 src_width
= ft_face
->glyph
->bitmap
.width
;
5683 src_height
= ft_face
->glyph
->bitmap
.rows
;
5685 if ( render_mode
== FT_RENDER_MODE_LCD
)
5693 rgb_interval
= src_pitch
;
5698 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5699 if ( x_shift
< 0 ) x_shift
= 0;
5700 if ( x_shift
+ (src_width
/ hmul
) > width
)
5701 x_shift
= width
- (src_width
/ hmul
);
5703 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5704 if ( y_shift
< 0 ) y_shift
= 0;
5705 if ( y_shift
+ (src_height
/ vmul
) > height
)
5706 y_shift
= height
- (src_height
/ vmul
);
5708 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5709 while ( src_height
)
5711 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5715 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5716 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5717 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5718 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5722 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5723 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5724 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5725 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5728 src
+= src_pitch
* vmul
;
5737 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5749 int contour
, point
= 0, first_pt
;
5750 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5751 TTPOLYGONHEADER
*pph
;
5753 DWORD pph_start
, cpfx
, type
;
5755 if(buflen
== 0) buf
= NULL
;
5757 if (needsTransform
&& buf
) {
5758 pFT_Outline_Transform(outline
, &transMat
);
5761 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5763 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5766 pph
->dwType
= TT_POLYGON_TYPE
;
5767 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5769 needed
+= sizeof(*pph
);
5771 while(point
<= outline
->contours
[contour
]) {
5772 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5773 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5774 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5778 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5781 } while(point
<= outline
->contours
[contour
] &&
5782 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5783 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5784 /* At the end of a contour Windows adds the start point, but
5786 if(point
> outline
->contours
[contour
] &&
5787 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5789 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5791 } else if(point
<= outline
->contours
[contour
] &&
5792 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5793 /* add closing pt for bezier */
5795 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5803 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5806 pph
->cb
= needed
- pph_start
;
5812 /* Convert the quadratic Beziers to cubic Beziers.
5813 The parametric eqn for a cubic Bezier is, from PLRM:
5814 r(t) = at^3 + bt^2 + ct + r0
5815 with the control points:
5820 A quadratic Bezier has the form:
5821 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5823 So equating powers of t leads to:
5824 r1 = 2/3 p1 + 1/3 p0
5825 r2 = 2/3 p1 + 1/3 p2
5826 and of course r0 = p0, r3 = p2
5829 int contour
, point
= 0, first_pt
;
5830 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5831 TTPOLYGONHEADER
*pph
;
5833 DWORD pph_start
, cpfx
, type
;
5834 FT_Vector cubic_control
[4];
5835 if(buflen
== 0) buf
= NULL
;
5837 if (needsTransform
&& buf
) {
5838 pFT_Outline_Transform(outline
, &transMat
);
5841 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5843 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5846 pph
->dwType
= TT_POLYGON_TYPE
;
5847 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5849 needed
+= sizeof(*pph
);
5851 while(point
<= outline
->contours
[contour
]) {
5852 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5853 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5854 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5857 if(type
== TT_PRIM_LINE
) {
5859 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5863 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5866 /* FIXME: Possible optimization in endpoint calculation
5867 if there are two consecutive curves */
5868 cubic_control
[0] = outline
->points
[point
-1];
5869 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5870 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5871 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5872 cubic_control
[0].x
>>= 1;
5873 cubic_control
[0].y
>>= 1;
5875 if(point
+1 > outline
->contours
[contour
])
5876 cubic_control
[3] = outline
->points
[first_pt
];
5878 cubic_control
[3] = outline
->points
[point
+1];
5879 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5880 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5881 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5882 cubic_control
[3].x
>>= 1;
5883 cubic_control
[3].y
>>= 1;
5886 /* r1 = 1/3 p0 + 2/3 p1
5887 r2 = 1/3 p2 + 2/3 p1 */
5888 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5889 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5890 cubic_control
[2] = cubic_control
[1];
5891 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5892 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5893 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5894 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5896 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5897 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5898 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5903 } while(point
<= outline
->contours
[contour
] &&
5904 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5905 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5906 /* At the end of a contour Windows adds the start point,
5907 but only for Beziers and we've already done that.
5909 if(point
<= outline
->contours
[contour
] &&
5910 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5911 /* This is the closing pt of a bezier, but we've already
5912 added it, so just inc point and carry on */
5919 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5922 pph
->cb
= needed
- pph_start
;
5928 FIXME("Unsupported format %d\n", format
);
5934 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5936 FT_Face ft_face
= font
->ft_face
;
5937 FT_WinFNT_HeaderRec winfnt_header
;
5938 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5939 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5940 font
->potm
->otmSize
= size
;
5942 #define TM font->potm->otmTextMetrics
5943 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5945 TM
.tmHeight
= winfnt_header
.pixel_height
;
5946 TM
.tmAscent
= winfnt_header
.ascent
;
5947 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5948 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5949 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5950 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5951 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5952 TM
.tmWeight
= winfnt_header
.weight
;
5954 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5955 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5956 TM
.tmFirstChar
= winfnt_header
.first_char
;
5957 TM
.tmLastChar
= winfnt_header
.last_char
;
5958 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5959 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5960 TM
.tmItalic
= winfnt_header
.italic
;
5961 TM
.tmUnderlined
= font
->underline
;
5962 TM
.tmStruckOut
= font
->strikeout
;
5963 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5964 TM
.tmCharSet
= winfnt_header
.charset
;
5968 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5969 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5970 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5971 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5972 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5973 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5974 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5975 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5977 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5978 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5980 TM
.tmLastChar
= 255;
5981 TM
.tmDefaultChar
= 32;
5982 TM
.tmBreakChar
= 32;
5983 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5984 TM
.tmUnderlined
= font
->underline
;
5985 TM
.tmStruckOut
= font
->strikeout
;
5986 /* NB inverted meaning of TMPF_FIXED_PITCH */
5987 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5988 TM
.tmCharSet
= font
->charset
;
5996 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5998 double scale_x
, scale_y
;
6002 scale_x
= (double)font
->aveWidth
;
6003 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6006 scale_x
= font
->scale_y
;
6008 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6009 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6011 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6012 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6014 SCALE_Y(ptm
->tmHeight
);
6015 SCALE_Y(ptm
->tmAscent
);
6016 SCALE_Y(ptm
->tmDescent
);
6017 SCALE_Y(ptm
->tmInternalLeading
);
6018 SCALE_Y(ptm
->tmExternalLeading
);
6019 SCALE_Y(ptm
->tmOverhang
);
6021 SCALE_X(ptm
->tmAveCharWidth
);
6022 SCALE_X(ptm
->tmMaxCharWidth
);
6028 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6030 double scale_x
, scale_y
;
6034 scale_x
= (double)font
->aveWidth
;
6035 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6038 scale_x
= font
->scale_y
;
6040 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6041 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6043 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6045 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6046 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6048 SCALE_Y(potm
->otmAscent
);
6049 SCALE_Y(potm
->otmDescent
);
6050 SCALE_Y(potm
->otmLineGap
);
6051 SCALE_Y(potm
->otmsCapEmHeight
);
6052 SCALE_Y(potm
->otmsXHeight
);
6053 SCALE_Y(potm
->otmrcFontBox
.top
);
6054 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6055 SCALE_X(potm
->otmrcFontBox
.left
);
6056 SCALE_X(potm
->otmrcFontBox
.right
);
6057 SCALE_Y(potm
->otmMacAscent
);
6058 SCALE_Y(potm
->otmMacDescent
);
6059 SCALE_Y(potm
->otmMacLineGap
);
6060 SCALE_X(potm
->otmptSubscriptSize
.x
);
6061 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6062 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6063 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6064 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6065 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6066 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6067 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6068 SCALE_Y(potm
->otmsStrikeoutSize
);
6069 SCALE_Y(potm
->otmsStrikeoutPosition
);
6070 SCALE_Y(potm
->otmsUnderscoreSize
);
6071 SCALE_Y(potm
->otmsUnderscorePosition
);
6077 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6081 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6083 /* Make sure that the font has sane width/height ratio */
6086 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6088 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6093 *ptm
= font
->potm
->otmTextMetrics
;
6094 scale_font_metrics(font
, ptm
);
6098 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6102 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6104 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6110 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6113 FT_Face ft_face
= font
->ft_face
;
6114 UINT needed
, lenfam
, lensty
;
6116 TT_HoriHeader
*pHori
;
6117 TT_Postscript
*pPost
;
6118 FT_Fixed x_scale
, y_scale
;
6119 WCHAR
*family_nameW
, *style_nameW
;
6120 static const WCHAR spaceW
[] = {' ', '\0'};
6122 INT ascent
, descent
;
6124 TRACE("font=%p\n", font
);
6126 if(!FT_IS_SCALABLE(ft_face
))
6129 needed
= sizeof(*font
->potm
);
6131 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6132 family_nameW
= strdupW(font
->name
);
6134 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6136 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6137 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6138 style_nameW
, lensty
/sizeof(WCHAR
));
6140 /* These names should be read from the TT name table */
6142 /* length of otmpFamilyName */
6145 /* length of otmpFaceName */
6146 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6147 needed
+= lenfam
; /* just the family name */
6149 needed
+= lenfam
+ lensty
; /* family + " " + style */
6152 /* length of otmpStyleName */
6155 /* length of otmpFullName */
6156 needed
+= lenfam
+ lensty
;
6159 x_scale
= ft_face
->size
->metrics
.x_scale
;
6160 y_scale
= ft_face
->size
->metrics
.y_scale
;
6162 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6164 FIXME("Can't find OS/2 table - not TT font?\n");
6168 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6170 FIXME("Can't find HHEA table - not TT font?\n");
6174 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6176 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6177 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6178 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6179 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6180 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6181 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6183 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6184 font
->potm
->otmSize
= needed
;
6186 #define TM font->potm->otmTextMetrics
6188 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6189 ascent
= pHori
->Ascender
;
6190 descent
= -pHori
->Descender
;
6192 ascent
= pOS2
->usWinAscent
;
6193 descent
= pOS2
->usWinDescent
;
6197 TM
.tmAscent
= font
->yMax
;
6198 TM
.tmDescent
= -font
->yMin
;
6199 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6201 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6202 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6203 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6204 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6207 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6210 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6212 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6213 ((ascent
+ descent
) -
6214 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6216 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6217 if (TM
.tmAveCharWidth
== 0) {
6218 TM
.tmAveCharWidth
= 1;
6220 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6221 TM
.tmWeight
= FW_REGULAR
;
6222 if (font
->fake_bold
)
6223 TM
.tmWeight
= FW_BOLD
;
6226 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6228 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6229 TM
.tmWeight
= pOS2
->usWeightClass
;
6231 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6232 TM
.tmWeight
= pOS2
->usWeightClass
;
6235 TM
.tmDigitizedAspectX
= 300;
6236 TM
.tmDigitizedAspectY
= 300;
6237 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6238 * symbol range to 0 - f0ff
6241 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6246 case 1257: /* Baltic */
6247 TM
.tmLastChar
= 0xf8fd;
6250 TM
.tmLastChar
= 0xf0ff;
6252 TM
.tmBreakChar
= 0x20;
6253 TM
.tmDefaultChar
= 0x1f;
6257 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6258 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6260 if(pOS2
->usFirstCharIndex
<= 1)
6261 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6262 else if (pOS2
->usFirstCharIndex
> 0xff)
6263 TM
.tmBreakChar
= 0x20;
6265 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6266 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6268 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6269 TM
.tmUnderlined
= font
->underline
;
6270 TM
.tmStruckOut
= font
->strikeout
;
6272 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6273 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6274 (pOS2
->version
== 0xFFFFU
||
6275 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6276 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6278 TM
.tmPitchAndFamily
= 0;
6280 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6282 case PAN_FAMILY_SCRIPT
:
6283 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6286 case PAN_FAMILY_DECORATIVE
:
6287 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6292 case PAN_FAMILY_TEXT_DISPLAY
:
6293 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6294 /* which is clearly not what the panose spec says. */
6296 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6297 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6298 TM
.tmPitchAndFamily
= FF_MODERN
;
6301 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6306 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6309 case PAN_SERIF_COVE
:
6310 case PAN_SERIF_OBTUSE_COVE
:
6311 case PAN_SERIF_SQUARE_COVE
:
6312 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6313 case PAN_SERIF_SQUARE
:
6314 case PAN_SERIF_THIN
:
6315 case PAN_SERIF_BONE
:
6316 case PAN_SERIF_EXAGGERATED
:
6317 case PAN_SERIF_TRIANGLE
:
6318 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6321 case PAN_SERIF_NORMAL_SANS
:
6322 case PAN_SERIF_OBTUSE_SANS
:
6323 case PAN_SERIF_PERP_SANS
:
6324 case PAN_SERIF_FLARED
:
6325 case PAN_SERIF_ROUNDED
:
6326 TM
.tmPitchAndFamily
|= FF_SWISS
;
6333 if(FT_IS_SCALABLE(ft_face
))
6334 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6336 if(FT_IS_SFNT(ft_face
))
6338 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6339 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6341 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6344 TM
.tmCharSet
= font
->charset
;
6346 font
->potm
->otmFiller
= 0;
6347 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6348 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6349 font
->potm
->otmfsType
= pOS2
->fsType
;
6350 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6351 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6352 font
->potm
->otmItalicAngle
= 0; /* POST table */
6353 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6354 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6355 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6356 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6357 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6358 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6359 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6360 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6361 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6362 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6363 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6364 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6365 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6366 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6367 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6368 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6369 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6370 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6371 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6372 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6373 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6374 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6375 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6376 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6378 font
->potm
->otmsUnderscoreSize
= 0;
6379 font
->potm
->otmsUnderscorePosition
= 0;
6381 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6382 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6386 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6387 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6388 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6389 strcpyW((WCHAR
*)cp
, family_nameW
);
6391 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6392 strcpyW((WCHAR
*)cp
, style_nameW
);
6394 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6395 strcpyW((WCHAR
*)cp
, family_nameW
);
6396 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6397 strcatW((WCHAR
*)cp
, spaceW
);
6398 strcatW((WCHAR
*)cp
, style_nameW
);
6399 cp
+= lenfam
+ lensty
;
6402 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6403 strcpyW((WCHAR
*)cp
, family_nameW
);
6404 strcatW((WCHAR
*)cp
, spaceW
);
6405 strcatW((WCHAR
*)cp
, style_nameW
);
6409 HeapFree(GetProcessHeap(), 0, style_nameW
);
6410 HeapFree(GetProcessHeap(), 0, family_nameW
);
6414 /*************************************************************
6415 * freetype_GetGlyphOutline
6417 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6418 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6420 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6425 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6426 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6430 EnterCriticalSection( &freetype_cs
);
6431 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6432 LeaveCriticalSection( &freetype_cs
);
6436 /*************************************************************
6437 * freetype_GetTextMetrics
6439 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6441 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6446 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6447 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6451 EnterCriticalSection( &freetype_cs
);
6452 ret
= get_text_metrics( physdev
->font
, metrics
);
6453 LeaveCriticalSection( &freetype_cs
);
6457 /*************************************************************
6458 * freetype_GetOutlineTextMetrics
6460 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6462 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6467 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6468 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6471 TRACE("font=%p\n", physdev
->font
);
6473 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6476 EnterCriticalSection( &freetype_cs
);
6478 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6480 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6482 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6483 scale_outline_font_metrics(physdev
->font
, potm
);
6485 ret
= physdev
->font
->potm
->otmSize
;
6487 LeaveCriticalSection( &freetype_cs
);
6491 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6493 HFONTLIST
*hfontlist
;
6494 child
->font
= alloc_font();
6495 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6496 if(!child
->font
->ft_face
)
6498 free_font(child
->font
);
6503 child
->font
->font_desc
= font
->font_desc
;
6504 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6505 child
->font
->orientation
= font
->orientation
;
6506 child
->font
->scale_y
= font
->scale_y
;
6507 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6508 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6509 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6510 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6511 child
->font
->base_font
= font
;
6512 list_add_head(&child_font_list
, &child
->font
->entry
);
6513 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6517 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6520 CHILD_FONT
*child_font
;
6523 font
= font
->base_font
;
6525 *linked_font
= font
;
6527 if((*glyph
= get_glyph_index(font
, c
)))
6529 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6533 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6535 if(!child_font
->font
)
6536 if(!load_child_font(font
, child_font
))
6539 if(!child_font
->font
->ft_face
)
6541 g
= get_glyph_index(child_font
->font
, c
);
6542 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6546 *linked_font
= child_font
->font
;
6553 /*************************************************************
6554 * freetype_GetCharWidth
6556 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6558 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6561 FT_UInt glyph_index
;
6562 GdiFont
*linked_font
;
6563 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6567 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6568 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6571 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6574 EnterCriticalSection( &freetype_cs
);
6575 for(c
= firstChar
; c
<= lastChar
; c
++) {
6576 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6577 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6578 &gm
, 0, NULL
, &identity
);
6579 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6581 LeaveCriticalSection( &freetype_cs
);
6585 /*************************************************************
6586 * freetype_GetCharABCWidths
6588 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6590 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6593 FT_UInt glyph_index
;
6594 GdiFont
*linked_font
;
6595 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6599 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6600 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6603 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6606 EnterCriticalSection( &freetype_cs
);
6608 for(c
= firstChar
; c
<= lastChar
; c
++) {
6609 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6610 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6611 &gm
, 0, NULL
, &identity
);
6612 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6613 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6614 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6615 FONT_GM(linked_font
,glyph_index
)->bbx
;
6617 LeaveCriticalSection( &freetype_cs
);
6621 /*************************************************************
6622 * freetype_GetCharABCWidthsI
6624 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6626 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6629 FT_UInt glyph_index
;
6630 GdiFont
*linked_font
;
6631 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6635 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6636 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6639 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6643 EnterCriticalSection( &freetype_cs
);
6645 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6647 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6648 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6649 &gm
, 0, NULL
, &identity
);
6650 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6651 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6652 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6653 - FONT_GM(linked_font
,c
)->bbx
;
6656 for(c
= 0; c
< count
; c
++) {
6657 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6658 &gm
, 0, NULL
, &identity
);
6659 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6660 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6661 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6662 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6665 LeaveCriticalSection( &freetype_cs
);
6669 /*************************************************************
6670 * freetype_GetTextExtentExPoint
6672 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6673 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6675 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6680 FT_UInt glyph_index
;
6681 GdiFont
*linked_font
;
6682 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6686 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6687 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6690 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6693 EnterCriticalSection( &freetype_cs
);
6696 get_text_metrics( physdev
->font
, &tm
);
6697 size
->cy
= tm
.tmHeight
;
6699 for(idx
= 0; idx
< count
; idx
++) {
6700 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6701 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6702 &gm
, 0, NULL
, &identity
);
6703 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6705 if (! pnfit
|| ext
<= max_ext
) {
6715 LeaveCriticalSection( &freetype_cs
);
6716 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6720 /*************************************************************
6721 * freetype_GetTextExtentExPointI
6723 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6724 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6726 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6731 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6735 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6736 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6739 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6742 EnterCriticalSection( &freetype_cs
);
6745 get_text_metrics(physdev
->font
, &tm
);
6746 size
->cy
= tm
.tmHeight
;
6748 for(idx
= 0; idx
< count
; idx
++) {
6749 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6750 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6752 if (! pnfit
|| ext
<= max_ext
) {
6762 LeaveCriticalSection( &freetype_cs
);
6763 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6767 /*************************************************************
6768 * freetype_GetFontData
6770 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6772 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6776 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6777 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6780 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6781 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6782 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6784 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6787 /*************************************************************
6788 * freetype_GetTextFace
6790 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6793 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6797 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6798 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6801 n
= strlenW(physdev
->font
->name
) + 1;
6804 lstrcpynW(str
, physdev
->font
->name
, count
);
6810 /*************************************************************
6811 * freetype_GetTextCharsetInfo
6813 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6815 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6819 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6820 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6822 if (fs
) *fs
= physdev
->font
->fs
;
6823 return physdev
->font
->charset
;
6826 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6828 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6829 struct list
*first_hfont
;
6833 EnterCriticalSection( &freetype_cs
);
6834 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6835 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6836 if(font
== linked_font
)
6837 *new_hfont
= dc
->hFont
;
6840 first_hfont
= list_head(&linked_font
->hfontlist
);
6841 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6843 LeaveCriticalSection( &freetype_cs
);
6847 /* Retrieve a list of supported Unicode ranges for a given font.
6848 * Can be called with NULL gs to calculate the buffer size. Returns
6849 * the number of ranges found.
6851 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6853 DWORD num_ranges
= 0;
6855 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6858 FT_ULong char_code
, char_code_prev
;
6861 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6863 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6864 face
->num_glyphs
, glyph_code
, char_code
);
6866 if (!glyph_code
) return 0;
6870 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6871 gs
->ranges
[0].cGlyphs
= 0;
6872 gs
->cGlyphsSupported
= 0;
6878 if (char_code
< char_code_prev
)
6880 ERR("expected increasing char code from FT_Get_Next_Char\n");
6883 if (char_code
- char_code_prev
> 1)
6888 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6889 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6890 gs
->cGlyphsSupported
++;
6895 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6896 gs
->cGlyphsSupported
++;
6898 char_code_prev
= char_code
;
6899 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6903 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6908 /*************************************************************
6909 * freetype_GetFontUnicodeRanges
6911 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6913 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6914 DWORD size
, num_ranges
;
6918 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6919 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6922 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6923 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6926 glyphset
->cbThis
= size
;
6927 glyphset
->cRanges
= num_ranges
;
6928 glyphset
->flAccel
= 0;
6933 /*************************************************************
6934 * freetype_FontIsLinked
6936 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6938 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6943 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6944 return dev
->funcs
->pFontIsLinked( dev
);
6948 EnterCriticalSection( &freetype_cs
);
6949 ret
= !list_empty(&physdev
->font
->child_fonts
);
6950 LeaveCriticalSection( &freetype_cs
);
6954 static BOOL
is_hinting_enabled(void)
6956 /* Use the >= 2.2.0 function if available */
6957 if(pFT_Get_TrueType_Engine_Type
)
6959 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6960 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6962 #ifdef FT_DRIVER_HAS_HINTER
6967 /* otherwise if we've been compiled with < 2.2.0 headers
6968 use the internal macro */
6969 mod
= pFT_Get_Module(library
, "truetype");
6970 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6978 static BOOL
is_subpixel_rendering_enabled( void )
6980 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6981 return pFT_Library_SetLcdFilter
&&
6982 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6988 /*************************************************************************
6989 * GetRasterizerCaps (GDI32.@)
6991 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6993 static int hinting
= -1;
6994 static int subpixel
= -1;
6998 hinting
= is_hinting_enabled();
6999 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
7002 if ( subpixel
== -1 )
7004 subpixel
= is_subpixel_rendering_enabled();
7005 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
7008 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7009 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
7011 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
7012 lprs
->nLanguageID
= 0;
7016 /*************************************************************
7017 * freetype_GdiRealizationInfo
7019 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7021 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7022 realization_info_t
*info
= ptr
;
7026 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7027 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7030 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7033 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7036 info
->cache_num
= physdev
->font
->cache_num
;
7037 info
->unknown2
= -1;
7041 /*************************************************************************
7042 * Kerning support for TrueType fonts
7044 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7046 struct TT_kern_table
7052 struct TT_kern_subtable
7061 USHORT horizontal
: 1;
7063 USHORT cross_stream
: 1;
7064 USHORT override
: 1;
7065 USHORT reserved1
: 4;
7071 struct TT_format0_kern_subtable
7075 USHORT entrySelector
;
7086 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7087 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7088 const USHORT
*glyph_to_char
,
7089 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7092 const struct TT_kern_pair
*tt_kern_pair
;
7094 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7096 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7098 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7099 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7100 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7102 if (!kern_pair
|| !cPairs
)
7105 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7107 nPairs
= min(nPairs
, cPairs
);
7109 for (i
= 0; i
< nPairs
; i
++)
7111 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7112 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7113 /* this algorithm appears to better match what Windows does */
7114 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7115 if (kern_pair
->iKernAmount
< 0)
7117 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7118 kern_pair
->iKernAmount
-= font
->ppem
;
7120 else if (kern_pair
->iKernAmount
> 0)
7122 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7123 kern_pair
->iKernAmount
+= font
->ppem
;
7125 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7127 TRACE("left %u right %u value %d\n",
7128 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7132 TRACE("copied %u entries\n", nPairs
);
7136 /*************************************************************
7137 * freetype_GetKerningPairs
7139 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7143 const struct TT_kern_table
*tt_kern_table
;
7144 const struct TT_kern_subtable
*tt_kern_subtable
;
7146 USHORT
*glyph_to_char
;
7148 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7150 if (!(font
= physdev
->font
))
7152 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7153 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7157 EnterCriticalSection( &freetype_cs
);
7158 if (font
->total_kern_pairs
!= (DWORD
)-1)
7160 if (cPairs
&& kern_pair
)
7162 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7163 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7165 else cPairs
= font
->total_kern_pairs
;
7167 LeaveCriticalSection( &freetype_cs
);
7171 font
->total_kern_pairs
= 0;
7173 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7175 if (length
== GDI_ERROR
)
7177 TRACE("no kerning data in the font\n");
7178 LeaveCriticalSection( &freetype_cs
);
7182 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7185 WARN("Out of memory\n");
7186 LeaveCriticalSection( &freetype_cs
);
7190 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7192 /* build a glyph index to char code map */
7193 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7196 WARN("Out of memory allocating a glyph index to char code map\n");
7197 HeapFree(GetProcessHeap(), 0, buf
);
7198 LeaveCriticalSection( &freetype_cs
);
7202 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7208 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7210 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7211 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7215 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7217 /* FIXME: This doesn't match what Windows does: it does some fancy
7218 * things with duplicate glyph index to char code mappings, while
7219 * we just avoid overriding existing entries.
7221 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7222 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7224 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7231 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7232 for (n
= 0; n
<= 65535; n
++)
7233 glyph_to_char
[n
] = (USHORT
)n
;
7236 tt_kern_table
= buf
;
7237 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7238 TRACE("version %u, nTables %u\n",
7239 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7241 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7243 for (i
= 0; i
< nTables
; i
++)
7245 struct TT_kern_subtable tt_kern_subtable_copy
;
7247 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7248 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7249 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7251 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7252 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7253 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7255 /* According to the TrueType specification this is the only format
7256 * that will be properly interpreted by Windows and OS/2
7258 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7260 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7262 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7263 glyph_to_char
, NULL
, 0);
7264 font
->total_kern_pairs
+= new_chunk
;
7266 if (!font
->kern_pairs
)
7267 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7268 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7270 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7271 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7273 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7274 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7277 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7279 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7282 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7283 HeapFree(GetProcessHeap(), 0, buf
);
7285 if (cPairs
&& kern_pair
)
7287 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7288 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7290 else cPairs
= font
->total_kern_pairs
;
7292 LeaveCriticalSection( &freetype_cs
);
7296 static const struct gdi_dc_funcs freetype_funcs
=
7298 NULL
, /* pAbortDoc */
7299 NULL
, /* pAbortPath */
7300 NULL
, /* pAlphaBlend */
7301 NULL
, /* pAngleArc */
7304 NULL
, /* pBeginPath */
7305 NULL
, /* pBlendImage */
7306 NULL
, /* pChoosePixelFormat */
7308 NULL
, /* pCloseFigure */
7309 NULL
, /* pCopyBitmap */
7310 NULL
, /* pCreateBitmap */
7311 NULL
, /* pCreateCompatibleDC */
7312 freetype_CreateDC
, /* pCreateDC */
7313 NULL
, /* pDeleteBitmap */
7314 freetype_DeleteDC
, /* pDeleteDC */
7315 NULL
, /* pDeleteObject */
7316 NULL
, /* pDescribePixelFormat */
7317 NULL
, /* pDeviceCapabilities */
7318 NULL
, /* pEllipse */
7320 NULL
, /* pEndPage */
7321 NULL
, /* pEndPath */
7322 freetype_EnumFonts
, /* pEnumFonts */
7323 NULL
, /* pEnumICMProfiles */
7324 NULL
, /* pExcludeClipRect */
7325 NULL
, /* pExtDeviceMode */
7326 NULL
, /* pExtEscape */
7327 NULL
, /* pExtFloodFill */
7328 NULL
, /* pExtSelectClipRgn */
7329 NULL
, /* pExtTextOut */
7330 NULL
, /* pFillPath */
7331 NULL
, /* pFillRgn */
7332 NULL
, /* pFlattenPath */
7333 freetype_FontIsLinked
, /* pFontIsLinked */
7334 NULL
, /* pFrameRgn */
7335 NULL
, /* pGdiComment */
7336 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7337 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7338 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7339 freetype_GetCharWidth
, /* pGetCharWidth */
7340 NULL
, /* pGetDeviceCaps */
7341 NULL
, /* pGetDeviceGammaRamp */
7342 freetype_GetFontData
, /* pGetFontData */
7343 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7344 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7345 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7346 NULL
, /* pGetICMProfile */
7347 NULL
, /* pGetImage */
7348 freetype_GetKerningPairs
, /* pGetKerningPairs */
7349 NULL
, /* pGetNearestColor */
7350 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7351 NULL
, /* pGetPixel */
7352 NULL
, /* pGetPixelFormat */
7353 NULL
, /* pGetSystemPaletteEntries */
7354 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7355 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7356 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7357 freetype_GetTextFace
, /* pGetTextFace */
7358 freetype_GetTextMetrics
, /* pGetTextMetrics */
7359 NULL
, /* pGradientFill */
7360 NULL
, /* pIntersectClipRect */
7361 NULL
, /* pInvertRgn */
7363 NULL
, /* pModifyWorldTransform */
7365 NULL
, /* pOffsetClipRgn */
7366 NULL
, /* pOffsetViewportOrg */
7367 NULL
, /* pOffsetWindowOrg */
7368 NULL
, /* pPaintRgn */
7371 NULL
, /* pPolyBezier */
7372 NULL
, /* pPolyBezierTo */
7373 NULL
, /* pPolyDraw */
7374 NULL
, /* pPolyPolygon */
7375 NULL
, /* pPolyPolyline */
7376 NULL
, /* pPolygon */
7377 NULL
, /* pPolyline */
7378 NULL
, /* pPolylineTo */
7379 NULL
, /* pPutImage */
7380 NULL
, /* pRealizeDefaultPalette */
7381 NULL
, /* pRealizePalette */
7382 NULL
, /* pRectangle */
7383 NULL
, /* pResetDC */
7384 NULL
, /* pRestoreDC */
7385 NULL
, /* pRoundRect */
7387 NULL
, /* pScaleViewportExt */
7388 NULL
, /* pScaleWindowExt */
7389 NULL
, /* pSelectBitmap */
7390 NULL
, /* pSelectBrush */
7391 NULL
, /* pSelectClipPath */
7392 freetype_SelectFont
, /* pSelectFont */
7393 NULL
, /* pSelectPalette */
7394 NULL
, /* pSelectPen */
7395 NULL
, /* pSetArcDirection */
7396 NULL
, /* pSetBkColor */
7397 NULL
, /* pSetBkMode */
7398 NULL
, /* pSetDCBrushColor */
7399 NULL
, /* pSetDCPenColor */
7400 NULL
, /* pSetDIBColorTable */
7401 NULL
, /* pSetDIBitsToDevice */
7402 NULL
, /* pSetDeviceClipping */
7403 NULL
, /* pSetDeviceGammaRamp */
7404 NULL
, /* pSetLayout */
7405 NULL
, /* pSetMapMode */
7406 NULL
, /* pSetMapperFlags */
7407 NULL
, /* pSetPixel */
7408 NULL
, /* pSetPixelFormat */
7409 NULL
, /* pSetPolyFillMode */
7410 NULL
, /* pSetROP2 */
7411 NULL
, /* pSetRelAbs */
7412 NULL
, /* pSetStretchBltMode */
7413 NULL
, /* pSetTextAlign */
7414 NULL
, /* pSetTextCharacterExtra */
7415 NULL
, /* pSetTextColor */
7416 NULL
, /* pSetTextJustification */
7417 NULL
, /* pSetViewportExt */
7418 NULL
, /* pSetViewportOrg */
7419 NULL
, /* pSetWindowExt */
7420 NULL
, /* pSetWindowOrg */
7421 NULL
, /* pSetWorldTransform */
7422 NULL
, /* pStartDoc */
7423 NULL
, /* pStartPage */
7424 NULL
, /* pStretchBlt */
7425 NULL
, /* pStretchDIBits */
7426 NULL
, /* pStrokeAndFillPath */
7427 NULL
, /* pStrokePath */
7428 NULL
, /* pSwapBuffers */
7429 NULL
, /* pUnrealizePalette */
7430 NULL
, /* pWidenPath */
7431 /* OpenGL not supported */
7434 #else /* HAVE_FREETYPE */
7436 /*************************************************************************/
7438 BOOL
WineEngInit(void)
7442 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7447 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7449 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7453 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7455 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7459 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7461 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7465 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7470 /*************************************************************************
7471 * GetRasterizerCaps (GDI32.@)
7473 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7475 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7477 lprs
->nLanguageID
= 0;
7481 #endif /* HAVE_FREETYPE */