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 int StyleOrdering(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 /* Add a style of face to a font family using an ordering of the list such
1471 that regular fonts come before bold and italic, and single styles come
1472 before compound styles. */
1473 static void AddFaceToFamily(Face
*face
, Family
*family
)
1477 LIST_FOR_EACH( entry
, &family
->faces
)
1479 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1480 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1482 list_add_before( entry
, &face
->entry
);
1485 static WCHAR
*prepend_at(WCHAR
*family
)
1492 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1494 strcpyW(str
+ 1, family
);
1495 HeapFree(GetProcessHeap(), 0, family
);
1499 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1501 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1502 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1504 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID() );
1510 else if (!strcmpiW( *name
, *english
))
1512 HeapFree( GetProcessHeap(), 0, *english
);
1518 *name
= prepend_at( *name
);
1519 *english
= prepend_at( *english
);
1523 /****************************************************************
1524 * NB This function stores the ptrs to the strings to save copying.
1525 * Don't free them after calling.
1527 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1529 Family
*family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1530 family
->FamilyName
= name
;
1531 family
->EnglishName
= english_name
;
1532 list_init( &family
->faces
);
1533 family
->replacement
= &family
->faces
;
1538 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1541 WCHAR
*name
, *english_name
;
1543 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1545 family
= find_family_from_name( name
);
1549 family
= create_family( name
, english_name
);
1550 list_add_tail( &font_list
, &family
->entry
);
1554 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1555 subst
->from
.name
= strdupW( english_name
);
1556 subst
->from
.charset
= -1;
1557 subst
->to
.name
= strdupW( name
);
1558 subst
->to
.charset
= -1;
1559 add_font_subst( &font_subst_list
, subst
, 0 );
1564 HeapFree( GetProcessHeap(), 0, name
);
1565 HeapFree( GetProcessHeap(), 0, english_name
);
1571 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1573 FT_Fixed version
= 0;
1576 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1577 if (header
) version
= header
->Font_Revision
;
1582 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1585 FT_ULong table_size
= 0;
1587 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1588 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1589 if (flags
== 0) flags
= NTM_REGULAR
;
1591 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1592 flags
|= NTM_PS_OPENTYPE
;
1597 #define ADDFONT_EXTERNAL_FONT 0x01
1598 #define ADDFONT_FORCE_BITMAP 0x02
1599 #define ADDFONT_ADD_TO_CACHE 0x04
1601 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
, FT_Long face_index
, DWORD flags
, BOOL vertical
)
1610 struct list
*face_elem_ptr
;
1611 FT_WinFNT_HeaderRec winfnt_header
;
1612 int internal_leading
;
1614 My_FT_Bitmap_Size
*size
= NULL
;
1617 if(!FT_IS_SCALABLE(ft_face
))
1618 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1620 family
= get_family( ft_face
, vertical
);
1622 StyleW
= towstr(CP_ACP
, ft_face
->style_name
);
1624 internal_leading
= 0;
1625 memset(&fs
, 0, sizeof(fs
));
1627 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1629 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1630 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1631 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1632 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1633 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1634 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1635 if(pOS2
->version
== 0) {
1638 if(pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1639 fs
.fsCsb
[0] |= FS_LATIN1
;
1641 fs
.fsCsb
[0] |= FS_SYMBOL
;
1644 else if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1646 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1647 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1648 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1650 internal_leading
= winfnt_header
.internal_leading
;
1653 version
= get_font_version( ft_face
);
1654 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1655 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1656 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1657 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1658 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1659 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1660 face
->font_version
, version
);
1661 if(version
<= face
->font_version
) {
1662 TRACE("Original font is newer so skipping this one\n");
1663 HeapFree(GetProcessHeap(), 0, StyleW
);
1666 TRACE("Replacing original with this one\n");
1667 list_remove(&face
->entry
);
1668 HeapFree(GetProcessHeap(), 0, face
->file
);
1669 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1670 HeapFree(GetProcessHeap(), 0, face
->FullName
);
1671 HeapFree(GetProcessHeap(), 0, face
);
1676 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1677 face
->cached_enum_data
= NULL
;
1678 face
->StyleName
= StyleW
;
1679 face
->FullName
= get_face_name(ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1682 face
->file
= strdupA(file
);
1683 face
->font_data_ptr
= NULL
;
1684 face
->font_data_size
= 0;
1689 face
->font_data_ptr
= font_data_ptr
;
1690 face
->font_data_size
= font_data_size
;
1692 face
->face_index
= face_index
;
1693 face
->ntmFlags
= get_ntm_flags( ft_face
);
1694 face
->font_version
= version
;
1695 face
->family
= family
;
1696 face
->vertical
= vertical
;
1697 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1700 if(FT_IS_SCALABLE(ft_face
)) {
1701 memset(&face
->size
, 0, sizeof(face
->size
));
1702 face
->scalable
= TRUE
;
1704 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1705 size
->height
, size
->width
, size
->size
>> 6,
1706 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1707 face
->size
.height
= size
->height
;
1708 face
->size
.width
= size
->width
;
1709 face
->size
.size
= size
->size
;
1710 face
->size
.x_ppem
= size
->x_ppem
;
1711 face
->size
.y_ppem
= size
->y_ppem
;
1712 face
->size
.internal_leading
= internal_leading
;
1713 face
->scalable
= FALSE
;
1716 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1717 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1718 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1719 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1721 if(face
->fs
.fsCsb
[0] == 0)
1725 /* let's see if we can find any interesting cmaps */
1726 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1727 switch(ft_face
->charmaps
[i
]->encoding
) {
1728 case FT_ENCODING_UNICODE
:
1729 case FT_ENCODING_APPLE_ROMAN
:
1730 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1732 case FT_ENCODING_MS_SYMBOL
:
1733 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1741 if(flags
& ADDFONT_ADD_TO_CACHE
)
1742 add_face_to_cache(face
);
1744 AddFaceToFamily(face
, family
);
1746 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1748 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1749 debugstr_w(StyleW
));
1752 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1757 FT_Long face_index
= 0, num_faces
;
1760 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1761 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1763 #ifdef HAVE_CARBON_CARBON_H
1766 char **mac_list
= expand_mac_font(file
);
1769 BOOL had_one
= FALSE
;
1771 for(cursor
= mac_list
; *cursor
; cursor
++)
1774 AddFontToList(*cursor
, NULL
, 0, flags
);
1775 HeapFree(GetProcessHeap(), 0, *cursor
);
1777 HeapFree(GetProcessHeap(), 0, mac_list
);
1782 #endif /* HAVE_CARBON_CARBON_H */
1787 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1788 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1791 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1792 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1796 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1800 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*/
1801 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1802 pFT_Done_Face(ft_face
);
1806 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1807 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1808 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1809 pFT_Done_Face(ft_face
);
1813 if(FT_IS_SFNT(ft_face
))
1815 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1816 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1817 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
))
1819 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1820 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1821 pFT_Done_Face(ft_face
);
1825 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1826 we don't want to load these. */
1827 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1831 if(!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1833 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1834 pFT_Done_Face(ft_face
);
1840 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1841 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1842 pFT_Done_Face(ft_face
);
1846 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1848 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1849 pFT_Done_Face(ft_face
);
1853 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1856 if (FT_HAS_VERTICAL(ft_face
))
1858 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1862 num_faces
= ft_face
->num_faces
;
1863 pFT_Done_Face(ft_face
);
1864 } while(num_faces
> ++face_index
);
1868 static void DumpFontList(void)
1872 struct list
*family_elem_ptr
, *face_elem_ptr
;
1874 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1875 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1876 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1877 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1878 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1879 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1881 TRACE(" %d", face
->size
.height
);
1888 /***********************************************************
1889 * The replacement list is a way to map an entire font
1890 * family onto another family. For example adding
1892 * [HKCU\Software\Wine\Fonts\Replacements]
1893 * "Wingdings"="Winedings"
1895 * would enumerate the Winedings font both as Winedings and
1896 * Wingdings. However if a real Wingdings font is present the
1897 * replacement does not take place.
1900 static void LoadReplaceList(void)
1903 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1908 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1909 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1911 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1912 &valuelen
, &datalen
, NULL
, NULL
);
1914 valuelen
++; /* returned value doesn't include room for '\0' */
1915 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1916 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1920 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1921 &dlen
) == ERROR_SUCCESS
) {
1922 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1923 /* "NewName"="Oldname" */
1924 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1926 if(!find_family_from_any_name(value
))
1928 Family
* const family
= find_family_from_any_name(data
);
1931 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
1932 if (new_family
!= NULL
)
1934 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
1935 new_family
->FamilyName
= strdupW(value
);
1936 new_family
->EnglishName
= NULL
;
1937 list_init(&new_family
->faces
);
1938 new_family
->replacement
= &family
->faces
;
1939 list_add_tail(&font_list
, &new_family
->entry
);
1944 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
1949 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
1951 /* reset dlen and vlen */
1955 HeapFree(GetProcessHeap(), 0, data
);
1956 HeapFree(GetProcessHeap(), 0, value
);
1961 static const WCHAR
*font_links_list
[] =
1963 Lucida_Sans_Unicode
,
1964 Microsoft_Sans_Serif
,
1968 static const struct font_links_defaults_list
1970 /* Keyed off substitution for "MS Shell Dlg" */
1971 const WCHAR
*shelldlg
;
1972 /* Maximum of four substitutes, plus terminating NULL pointer */
1973 const WCHAR
*substitutes
[5];
1974 } font_links_defaults_list
[] =
1976 /* Non East-Asian */
1977 { Tahoma
, /* FIXME unverified ordering */
1978 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
1980 /* Below lists are courtesy of
1981 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1985 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
1987 /* Chinese Simplified */
1989 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
1993 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
1995 /* Chinese Traditional */
1997 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2002 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2004 SYSTEM_LINKS
*font_link
;
2006 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2008 if(!strcmpiW(font_link
->font_name
, name
))
2015 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2027 SYSTEM_LINKS
*font_link
;
2029 psub
= get_font_subst(&font_subst_list
, name
, -1);
2030 /* Don't store fonts that are only substitutes for other fonts */
2033 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2037 font_link
= find_font_link(name
);
2038 if (font_link
== NULL
)
2040 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2041 font_link
->font_name
= strdupW(name
);
2042 list_init(&font_link
->links
);
2043 list_add_tail(&system_links
, &font_link
->entry
);
2046 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2047 for (i
= 0; values
[i
] != NULL
; i
++)
2049 const struct list
*face_list
;
2050 CHILD_FONT
*child_font
;
2053 if (!strcmpiW(name
,value
))
2055 psub
= get_font_subst(&font_subst_list
, value
, -1);
2057 value
= psub
->to
.name
;
2058 family
= find_family_from_name(value
);
2062 /* Use first extant filename for this Family */
2063 face_list
= get_face_list_from_family(family
);
2064 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2068 file
= strrchr(face
->file
, '/');
2077 fileW
= towstr(CP_UNIXCP
, file
);
2079 face
= find_face_from_filename(fileW
, value
);
2082 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2086 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2087 child_font
->face
= face
;
2088 child_font
->font
= NULL
;
2089 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2090 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2091 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2092 list_add_tail(&font_link
->links
, &child_font
->entry
);
2094 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2095 HeapFree(GetProcessHeap(), 0, fileW
);
2101 /*************************************************************
2104 static BOOL
init_system_links(void)
2108 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2109 WCHAR
*value
, *data
;
2110 WCHAR
*entry
, *next
;
2111 SYSTEM_LINKS
*font_link
, *system_font_link
;
2112 CHILD_FONT
*child_font
;
2113 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2114 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2115 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2120 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2122 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2123 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2124 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2125 val_len
= max_val
+ 1;
2126 data_len
= max_data
;
2128 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2130 psub
= get_font_subst(&font_subst_list
, value
, -1);
2131 /* Don't store fonts that are only substitutes for other fonts */
2134 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2137 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2138 font_link
->font_name
= strdupW(value
);
2139 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2140 list_init(&font_link
->links
);
2141 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2144 CHILD_FONT
*child_font
;
2146 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2148 next
= entry
+ strlenW(entry
) + 1;
2150 face_name
= strchrW(entry
, ',');
2154 while(isspaceW(*face_name
))
2157 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2159 face_name
= psub
->to
.name
;
2161 face
= find_face_from_filename(entry
, face_name
);
2164 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2168 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2169 child_font
->face
= face
;
2170 child_font
->font
= NULL
;
2171 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2172 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2173 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2174 list_add_tail(&font_link
->links
, &child_font
->entry
);
2176 list_add_tail(&system_links
, &font_link
->entry
);
2178 val_len
= max_val
+ 1;
2179 data_len
= max_data
;
2182 HeapFree(GetProcessHeap(), 0, value
);
2183 HeapFree(GetProcessHeap(), 0, data
);
2188 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2190 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2194 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2196 const FontSubst
*psub2
;
2197 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2199 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2201 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2202 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2204 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2205 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2207 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2209 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2215 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2218 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2219 system_font_link
->font_name
= strdupW(System
);
2220 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2221 list_init(&system_font_link
->links
);
2223 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2226 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2227 child_font
->face
= face
;
2228 child_font
->font
= NULL
;
2229 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2230 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2231 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2232 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2234 font_link
= find_font_link(Tahoma
);
2235 if (font_link
!= NULL
)
2237 CHILD_FONT
*font_link_entry
;
2238 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2240 CHILD_FONT
*new_child
;
2241 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2242 new_child
->face
= font_link_entry
->face
;
2243 new_child
->font
= NULL
;
2244 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2245 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2246 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2249 list_add_tail(&system_links
, &system_font_link
->entry
);
2253 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2256 struct dirent
*dent
;
2257 char path
[MAX_PATH
];
2259 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2261 dir
= opendir(dirname
);
2263 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2266 while((dent
= readdir(dir
)) != NULL
) {
2267 struct stat statbuf
;
2269 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2272 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2274 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2276 if(stat(path
, &statbuf
) == -1)
2278 WARN("Can't stat %s\n", debugstr_a(path
));
2281 if(S_ISDIR(statbuf
.st_mode
))
2282 ReadFontDir(path
, external_fonts
);
2285 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2286 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2287 AddFontToList(path
, NULL
, 0, addfont_flags
);
2294 static void load_fontconfig_fonts(void)
2296 #ifdef SONAME_LIBFONTCONFIG
2297 void *fc_handle
= NULL
;
2306 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2308 TRACE("Wine cannot find the fontconfig library (%s).\n",
2309 SONAME_LIBFONTCONFIG
);
2312 #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;}
2313 LOAD_FUNCPTR(FcConfigGetCurrent
);
2314 LOAD_FUNCPTR(FcFontList
);
2315 LOAD_FUNCPTR(FcFontSetDestroy
);
2316 LOAD_FUNCPTR(FcInit
);
2317 LOAD_FUNCPTR(FcObjectSetAdd
);
2318 LOAD_FUNCPTR(FcObjectSetCreate
);
2319 LOAD_FUNCPTR(FcObjectSetDestroy
);
2320 LOAD_FUNCPTR(FcPatternCreate
);
2321 LOAD_FUNCPTR(FcPatternDestroy
);
2322 LOAD_FUNCPTR(FcPatternGetBool
);
2323 LOAD_FUNCPTR(FcPatternGetString
);
2326 if(!pFcInit()) return;
2328 config
= pFcConfigGetCurrent();
2329 pat
= pFcPatternCreate();
2330 os
= pFcObjectSetCreate();
2331 pFcObjectSetAdd(os
, FC_FILE
);
2332 pFcObjectSetAdd(os
, FC_SCALABLE
);
2333 fontset
= pFcFontList(config
, pat
, os
);
2334 if(!fontset
) return;
2335 for(i
= 0; i
< fontset
->nfont
; i
++) {
2338 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2340 TRACE("fontconfig: %s\n", file
);
2342 /* We're just interested in OT/TT fonts for now, so this hack just
2343 picks up the scalable fonts without extensions .pf[ab] to save time
2344 loading every other font */
2346 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2348 TRACE("not scalable\n");
2352 len
= strlen( file
);
2353 if(len
< 4) continue;
2354 ext
= &file
[ len
- 3 ];
2355 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2356 AddFontToList(file
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2358 pFcFontSetDestroy(fontset
);
2359 pFcObjectSetDestroy(os
);
2360 pFcPatternDestroy(pat
);
2366 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2369 const char *data_dir
= wine_get_data_dir();
2371 if (!data_dir
) data_dir
= wine_get_build_dir();
2378 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2380 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2382 strcpy(unix_name
, data_dir
);
2383 strcat(unix_name
, "/fonts/");
2385 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2387 EnterCriticalSection( &freetype_cs
);
2388 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2389 LeaveCriticalSection( &freetype_cs
);
2390 HeapFree(GetProcessHeap(), 0, unix_name
);
2395 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2397 static const WCHAR slashW
[] = {'\\','\0'};
2399 WCHAR windowsdir
[MAX_PATH
];
2402 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2403 strcatW(windowsdir
, fontsW
);
2404 strcatW(windowsdir
, slashW
);
2405 strcatW(windowsdir
, file
);
2406 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2407 EnterCriticalSection( &freetype_cs
);
2408 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2409 LeaveCriticalSection( &freetype_cs
);
2410 HeapFree(GetProcessHeap(), 0, unixname
);
2415 static void load_system_fonts(void)
2418 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2419 const WCHAR
* const *value
;
2421 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2424 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2425 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2426 strcatW(windowsdir
, fontsW
);
2427 for(value
= SystemFontValues
; *value
; value
++) {
2428 dlen
= sizeof(data
);
2429 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2433 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2434 if((unixname
= wine_get_unix_file_name(pathW
))) {
2435 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2436 HeapFree(GetProcessHeap(), 0, unixname
);
2439 load_font_from_data_dir(data
);
2446 /*************************************************************
2448 * This adds registry entries for any externally loaded fonts
2449 * (fonts from fontconfig or FontDirs). It also deletes entries
2450 * of no longer existing fonts.
2453 static void update_reg_entries(void)
2455 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2460 struct list
*family_elem_ptr
, *face_elem_ptr
;
2462 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2463 static const WCHAR spaceW
[] = {' ', '\0'};
2466 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2467 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2468 ERR("Can't create Windows font reg key\n");
2472 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2473 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2474 ERR("Can't create Windows font reg key\n");
2478 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2479 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2480 ERR("Can't create external font reg key\n");
2484 /* enumerate the fonts and add external ones to the two keys */
2486 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2487 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2488 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2489 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2490 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2491 if(!face
->external
) continue;
2493 if (!(face
->ntmFlags
& NTM_REGULAR
))
2494 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2495 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2496 strcpyW(valueW
, family
->FamilyName
);
2497 if(len
!= len_fam
) {
2498 strcatW(valueW
, spaceW
);
2499 strcatW(valueW
, face
->StyleName
);
2501 strcatW(valueW
, TrueType
);
2503 file
= wine_get_dos_file_name(face
->file
);
2505 len
= strlenW(file
) + 1;
2508 if((path
= strrchr(face
->file
, '/')) == NULL
)
2512 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2514 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2515 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2517 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2518 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2519 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2521 HeapFree(GetProcessHeap(), 0, file
);
2522 HeapFree(GetProcessHeap(), 0, valueW
);
2526 if(external_key
) RegCloseKey(external_key
);
2527 if(win9x_key
) RegCloseKey(win9x_key
);
2528 if(winnt_key
) RegCloseKey(winnt_key
);
2532 static void delete_external_font_keys(void)
2534 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2535 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2539 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2540 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2541 ERR("Can't create Windows font reg key\n");
2545 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2546 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2547 ERR("Can't create Windows font reg key\n");
2551 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2552 ERR("Can't create external font reg key\n");
2556 /* Delete all external fonts added last time */
2558 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2559 &valuelen
, &datalen
, NULL
, NULL
);
2560 valuelen
++; /* returned value doesn't include room for '\0' */
2561 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2562 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2564 dlen
= datalen
* sizeof(WCHAR
);
2567 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2568 &dlen
) == ERROR_SUCCESS
) {
2570 RegDeleteValueW(winnt_key
, valueW
);
2571 RegDeleteValueW(win9x_key
, valueW
);
2572 /* reset dlen and vlen */
2576 HeapFree(GetProcessHeap(), 0, data
);
2577 HeapFree(GetProcessHeap(), 0, valueW
);
2579 /* Delete the old external fonts key */
2580 RegCloseKey(external_key
);
2581 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2584 if(win9x_key
) RegCloseKey(win9x_key
);
2585 if(winnt_key
) RegCloseKey(winnt_key
);
2588 /*************************************************************
2589 * WineEngAddFontResourceEx
2592 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2598 if (ft_handle
) /* do it only if we have freetype up and running */
2603 FIXME("Ignoring flags %x\n", flags
);
2605 if((unixname
= wine_get_unix_file_name(file
)))
2607 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2609 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2610 EnterCriticalSection( &freetype_cs
);
2611 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2612 LeaveCriticalSection( &freetype_cs
);
2613 HeapFree(GetProcessHeap(), 0, unixname
);
2615 if (!ret
&& !strchrW(file
, '\\')) {
2616 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2617 ret
= load_font_from_winfonts_dir(file
);
2619 /* Try in datadir/fonts (or builddir/fonts),
2620 * needed for Magic the Gathering Online
2622 ret
= load_font_from_data_dir(file
);
2629 /*************************************************************
2630 * WineEngAddFontMemResourceEx
2633 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2637 if (ft_handle
) /* do it only if we have freetype up and running */
2639 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2641 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2642 memcpy(pFontCopy
, pbFont
, cbFont
);
2644 EnterCriticalSection( &freetype_cs
);
2645 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2646 LeaveCriticalSection( &freetype_cs
);
2650 TRACE("AddFontToList failed\n");
2651 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2654 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2655 * For now return something unique but quite random
2657 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2658 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2665 /*************************************************************
2666 * WineEngRemoveFontResourceEx
2669 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2672 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2676 static const struct nls_update_font_list
2678 UINT ansi_cp
, oem_cp
;
2679 const char *oem
, *fixed
, *system
;
2680 const char *courier
, *serif
, *small
, *sserif
;
2681 /* these are for font substitutes */
2682 const char *shelldlg
, *tmsrmn
;
2683 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2687 const char *from
, *to
;
2688 } arial_0
, courier_new_0
, times_new_roman_0
;
2689 } nls_update_font_list
[] =
2691 /* Latin 1 (United States) */
2692 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2693 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2694 "Tahoma","Times New Roman",
2695 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2698 /* Latin 1 (Multilingual) */
2699 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2700 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2701 "Tahoma","Times New Roman", /* FIXME unverified */
2702 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2705 /* Eastern Europe */
2706 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2707 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2708 "Tahoma","Times New Roman", /* FIXME unverified */
2709 "Fixedsys,238", "System,238",
2710 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2711 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2712 { "Arial CE,0", "Arial,238" },
2713 { "Courier New CE,0", "Courier New,238" },
2714 { "Times New Roman CE,0", "Times New Roman,238" }
2717 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2718 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2719 "Tahoma","Times New Roman", /* FIXME unverified */
2720 "Fixedsys,204", "System,204",
2721 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2722 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2723 { "Arial Cyr,0", "Arial,204" },
2724 { "Courier New Cyr,0", "Courier New,204" },
2725 { "Times New Roman Cyr,0", "Times New Roman,204" }
2728 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2729 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2730 "Tahoma","Times New Roman", /* FIXME unverified */
2731 "Fixedsys,161", "System,161",
2732 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2733 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2734 { "Arial Greek,0", "Arial,161" },
2735 { "Courier New Greek,0", "Courier New,161" },
2736 { "Times New Roman Greek,0", "Times New Roman,161" }
2739 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2740 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2741 "Tahoma","Times New Roman", /* FIXME unverified */
2742 "Fixedsys,162", "System,162",
2743 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2744 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2745 { "Arial Tur,0", "Arial,162" },
2746 { "Courier New Tur,0", "Courier New,162" },
2747 { "Times New Roman Tur,0", "Times New Roman,162" }
2750 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2751 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2752 "Tahoma","Times New Roman", /* FIXME unverified */
2753 "Fixedsys,177", "System,177",
2754 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2755 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2759 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2760 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2761 "Tahoma","Times New Roman", /* FIXME unverified */
2762 "Fixedsys,178", "System,178",
2763 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2764 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2768 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2769 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2770 "Tahoma","Times New Roman", /* FIXME unverified */
2771 "Fixedsys,186", "System,186",
2772 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2773 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2774 { "Arial Baltic,0", "Arial,186" },
2775 { "Courier New Baltic,0", "Courier New,186" },
2776 { "Times New Roman Baltic,0", "Times New Roman,186" }
2779 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2780 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2781 "Tahoma","Times New Roman", /* FIXME unverified */
2782 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2786 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2787 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2788 "Tahoma","Times New Roman", /* FIXME unverified */
2789 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2793 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2794 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2795 "MS UI Gothic","MS Serif",
2796 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2799 /* Chinese Simplified */
2800 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2801 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2802 "SimSun", "NSimSun",
2803 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2807 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2808 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2810 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2813 /* Chinese Traditional */
2814 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2815 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2816 "PMingLiU", "MingLiU",
2817 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2822 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2824 return ( ansi_cp
== 932 /* CP932 for Japanese */
2825 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2826 || ansi_cp
== 949 /* CP949 for Korean */
2827 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2830 static inline HKEY
create_fonts_NT_registry_key(void)
2834 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2835 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2839 static inline HKEY
create_fonts_9x_registry_key(void)
2843 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2844 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2848 static inline HKEY
create_config_fonts_registry_key(void)
2852 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2853 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2857 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2859 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2860 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2861 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2862 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2865 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2868 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2870 RegDeleteValueA(hkey
, name
);
2873 static void update_font_info(void)
2875 char buf
[40], cpbuf
[40];
2878 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2881 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2884 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2885 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2886 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2887 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2888 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2890 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2891 if (is_dbcs_ansi_cp(ansi_cp
))
2892 use_default_fallback
= TRUE
;
2895 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2897 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2902 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2904 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2906 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2909 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2913 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2914 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2916 hkey
= create_config_fonts_registry_key();
2917 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2918 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2919 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2922 hkey
= create_fonts_NT_registry_key();
2923 add_font_list(hkey
, &nls_update_font_list
[i
]);
2926 hkey
= create_fonts_9x_registry_key();
2927 add_font_list(hkey
, &nls_update_font_list
[i
]);
2930 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2932 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2933 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2934 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2935 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2937 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2938 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2939 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2940 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2941 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2942 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2943 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2944 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2946 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2947 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2948 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2956 /* Delete the FontSubstitutes from other locales */
2957 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2959 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2960 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2961 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2967 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2970 static BOOL
init_freetype(void)
2972 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2975 "Wine cannot find the FreeType font library. To enable Wine to\n"
2976 "use TrueType fonts please install a version of FreeType greater than\n"
2977 "or equal to 2.0.5.\n"
2978 "http://www.freetype.org\n");
2982 #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;}
2984 LOAD_FUNCPTR(FT_Done_Face
)
2985 LOAD_FUNCPTR(FT_Get_Char_Index
)
2986 LOAD_FUNCPTR(FT_Get_First_Char
)
2987 LOAD_FUNCPTR(FT_Get_Module
)
2988 LOAD_FUNCPTR(FT_Get_Next_Char
)
2989 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2990 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2991 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2992 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
2993 LOAD_FUNCPTR(FT_Init_FreeType
)
2994 LOAD_FUNCPTR(FT_Library_Version
)
2995 LOAD_FUNCPTR(FT_Load_Glyph
)
2996 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
2997 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2998 #ifndef FT_MULFIX_INLINED
2999 LOAD_FUNCPTR(FT_MulFix
)
3001 LOAD_FUNCPTR(FT_New_Face
)
3002 LOAD_FUNCPTR(FT_New_Memory_Face
)
3003 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3004 LOAD_FUNCPTR(FT_Outline_Transform
)
3005 LOAD_FUNCPTR(FT_Outline_Translate
)
3006 LOAD_FUNCPTR(FT_Render_Glyph
)
3007 LOAD_FUNCPTR(FT_Select_Charmap
)
3008 LOAD_FUNCPTR(FT_Set_Charmap
)
3009 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3010 LOAD_FUNCPTR(FT_Vector_Transform
)
3011 LOAD_FUNCPTR(FT_Vector_Unit
)
3013 /* Don't warn if these ones are missing */
3014 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3015 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3016 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3019 if(pFT_Init_FreeType(&library
) != 0) {
3020 ERR("Can't init FreeType library\n");
3021 wine_dlclose(ft_handle
, NULL
, 0);
3025 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3027 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3028 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3029 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3030 ((FT_Version
.patch
) & 0x0000ff);
3032 font_driver
= &freetype_funcs
;
3037 "Wine cannot find certain functions that it needs inside the FreeType\n"
3038 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3039 "FreeType to at least version 2.1.4.\n"
3040 "http://www.freetype.org\n");
3041 wine_dlclose(ft_handle
, NULL
, 0);
3046 static void init_font_list(void)
3048 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3049 static const WCHAR pathW
[] = {'P','a','t','h',0};
3051 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3052 WCHAR windowsdir
[MAX_PATH
];
3055 const char *data_dir
;
3057 delete_external_font_keys();
3059 /* load the system bitmap fonts */
3060 load_system_fonts();
3062 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3063 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3064 strcatW(windowsdir
, fontsW
);
3065 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3067 ReadFontDir(unixname
, FALSE
);
3068 HeapFree(GetProcessHeap(), 0, unixname
);
3071 /* load the system truetype fonts */
3072 data_dir
= wine_get_data_dir();
3073 if (!data_dir
) data_dir
= wine_get_build_dir();
3074 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3076 strcpy(unixname
, data_dir
);
3077 strcat(unixname
, "/fonts/");
3078 ReadFontDir(unixname
, TRUE
);
3079 HeapFree(GetProcessHeap(), 0, unixname
);
3082 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3083 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3084 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3086 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3087 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3088 &hkey
) == ERROR_SUCCESS
)
3090 LPWSTR data
, valueW
;
3091 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3092 &valuelen
, &datalen
, NULL
, NULL
);
3094 valuelen
++; /* returned value doesn't include room for '\0' */
3095 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3096 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3099 dlen
= datalen
* sizeof(WCHAR
);
3101 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3102 &dlen
) == ERROR_SUCCESS
)
3104 if(data
[0] && (data
[1] == ':'))
3106 if((unixname
= wine_get_unix_file_name(data
)))
3108 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3109 HeapFree(GetProcessHeap(), 0, unixname
);
3112 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3114 WCHAR pathW
[MAX_PATH
];
3115 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3118 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3119 if((unixname
= wine_get_unix_file_name(pathW
)))
3121 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3122 HeapFree(GetProcessHeap(), 0, unixname
);
3125 load_font_from_data_dir(data
);
3127 /* reset dlen and vlen */
3132 HeapFree(GetProcessHeap(), 0, data
);
3133 HeapFree(GetProcessHeap(), 0, valueW
);
3137 load_fontconfig_fonts();
3139 /* then look in any directories that we've specified in the config file */
3140 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3141 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3147 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3149 len
+= sizeof(WCHAR
);
3150 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3151 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3153 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3154 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3155 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3156 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3160 LPSTR next
= strchr( ptr
, ':' );
3161 if (next
) *next
++ = 0;
3162 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3163 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3165 strcpy( unixname
, home
);
3166 strcat( unixname
, ptr
+ 1 );
3167 ReadFontDir( unixname
, TRUE
);
3168 HeapFree( GetProcessHeap(), 0, unixname
);
3171 ReadFontDir( ptr
, TRUE
);
3174 HeapFree( GetProcessHeap(), 0, valueA
);
3176 HeapFree( GetProcessHeap(), 0, valueW
);
3182 /* Mac default font locations. */
3183 ReadFontDir( "/Library/Fonts", TRUE
);
3184 ReadFontDir( "/Network/Library/Fonts", TRUE
);
3185 ReadFontDir( "/System/Library/Fonts", TRUE
);
3186 if ((home
= getenv( "HOME" )))
3188 unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(home
)+15 );
3189 strcpy( unixname
, home
);
3190 strcat( unixname
, "/Library/Fonts" );
3191 ReadFontDir( unixname
, TRUE
);
3192 HeapFree( GetProcessHeap(), 0, unixname
);
3197 static BOOL
move_to_front(const WCHAR
*name
)
3199 Family
*family
, *cursor2
;
3200 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3202 if(!strcmpiW(family
->FamilyName
, name
))
3204 list_remove(&family
->entry
);
3205 list_add_head(&font_list
, &family
->entry
);
3212 static BOOL
set_default(const WCHAR
**name_list
)
3216 if (move_to_front(*name_list
)) return TRUE
;
3223 static void reorder_font_list(void)
3225 set_default( default_serif_list
);
3226 set_default( default_fixed_list
);
3227 set_default( default_sans_list
);
3230 /*************************************************************
3233 * Initialize FreeType library and create a list of available faces
3235 BOOL
WineEngInit(void)
3237 HKEY hkey_font_cache
;
3241 /* update locale dependent font info in registry */
3244 if(!init_freetype()) return FALSE
;
3246 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3248 ERR("Failed to create font mutex\n");
3251 WaitForSingleObject(font_mutex
, INFINITE
);
3253 create_font_cache_key(&hkey_font_cache
, &disposition
);
3255 if(disposition
== REG_CREATED_NEW_KEY
)
3258 load_font_list_from_cache(hkey_font_cache
);
3260 RegCloseKey(hkey_font_cache
);
3262 reorder_font_list();
3269 if(disposition
== REG_CREATED_NEW_KEY
)
3270 update_reg_entries();
3272 init_system_links();
3274 ReleaseMutex(font_mutex
);
3279 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3282 TT_HoriHeader
*pHori
;
3286 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3287 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3289 if(height
== 0) height
= 16;
3291 /* Calc. height of EM square:
3293 * For +ve lfHeight we have
3294 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3295 * Re-arranging gives:
3296 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3298 * For -ve lfHeight we have
3300 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3301 * with il = winAscent + winDescent - units_per_em]
3306 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3307 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3308 pHori
->Ascender
- pHori
->Descender
);
3310 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3311 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3319 static struct font_mapping
*map_font_file( const char *name
)
3321 struct font_mapping
*mapping
;
3325 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3326 if (fstat( fd
, &st
) == -1) goto error
;
3328 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3330 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3332 mapping
->refcount
++;
3337 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3340 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3343 if (mapping
->data
== MAP_FAILED
)
3345 HeapFree( GetProcessHeap(), 0, mapping
);
3348 mapping
->refcount
= 1;
3349 mapping
->dev
= st
.st_dev
;
3350 mapping
->ino
= st
.st_ino
;
3351 mapping
->size
= st
.st_size
;
3352 list_add_tail( &mappings_list
, &mapping
->entry
);
3360 static void unmap_font_file( struct font_mapping
*mapping
)
3362 if (!--mapping
->refcount
)
3364 list_remove( &mapping
->entry
);
3365 munmap( mapping
->data
, mapping
->size
);
3366 HeapFree( GetProcessHeap(), 0, mapping
);
3370 static LONG
load_VDMX(GdiFont
*, LONG
);
3372 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3379 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3383 if (!(font
->mapping
= map_font_file( face
->file
)))
3385 WARN("failed to map %s\n", debugstr_a(face
->file
));
3388 data_ptr
= font
->mapping
->data
;
3389 data_size
= font
->mapping
->size
;
3393 data_ptr
= face
->font_data_ptr
;
3394 data_size
= face
->font_data_size
;
3397 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3399 ERR("FT_New_Face rets %d\n", err
);
3403 /* set it here, as load_VDMX needs it */
3404 font
->ft_face
= ft_face
;
3406 if(FT_IS_SCALABLE(ft_face
)) {
3407 /* load the VDMX table if we have one */
3408 font
->ppem
= load_VDMX(font
, height
);
3410 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3411 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3413 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3414 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3416 font
->ppem
= height
;
3417 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3418 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3424 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3426 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3427 a single face with the requested charset. The idea is to check if
3428 the selected font supports the current ANSI codepage, if it does
3429 return the corresponding charset, else return the first charset */
3432 int acp
= GetACP(), i
;
3436 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3438 const SYSTEM_LINKS
*font_link
;
3440 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
3441 return csi
.ciCharset
;
3443 font_link
= find_font_link(family_name
);
3444 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
3445 return csi
.ciCharset
;
3448 for(i
= 0; i
< 32; i
++) {
3450 if(face
->fs
.fsCsb
[0] & fs0
) {
3451 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3453 return csi
.ciCharset
;
3456 FIXME("TCI failing on %x\n", fs0
);
3460 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3461 face
->fs
.fsCsb
[0], face
->file
);
3463 return DEFAULT_CHARSET
;
3466 static GdiFont
*alloc_font(void)
3468 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3470 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3471 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3473 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3474 ret
->total_kern_pairs
= (DWORD
)-1;
3475 ret
->kern_pairs
= NULL
;
3476 list_init(&ret
->hfontlist
);
3477 list_init(&ret
->child_fonts
);
3481 static void free_font(GdiFont
*font
)
3483 struct list
*cursor
, *cursor2
;
3486 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3488 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3489 list_remove(cursor
);
3491 free_font(child
->font
);
3492 HeapFree(GetProcessHeap(), 0, child
);
3495 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3497 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3498 DeleteObject(hfontlist
->hfont
);
3499 list_remove(&hfontlist
->entry
);
3500 HeapFree(GetProcessHeap(), 0, hfontlist
);
3503 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3504 if (font
->mapping
) unmap_font_file( font
->mapping
);
3505 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3506 HeapFree(GetProcessHeap(), 0, font
->potm
);
3507 HeapFree(GetProcessHeap(), 0, font
->name
);
3508 for (i
= 0; i
< font
->gmsize
; i
++)
3509 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3510 HeapFree(GetProcessHeap(), 0, font
->gm
);
3511 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3512 HeapFree(GetProcessHeap(), 0, font
);
3516 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3518 FT_Face ft_face
= font
->ft_face
;
3522 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3529 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3531 /* make sure value of len is the value freetype says it needs */
3534 FT_ULong needed
= 0;
3535 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3536 if( !err
&& needed
< len
) len
= needed
;
3538 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3541 TRACE("Can't find table %c%c%c%c\n",
3542 /* bytes were reversed */
3543 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3544 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3550 /*************************************************************
3553 * load the vdmx entry for the specified height
3556 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3557 ( ( (FT_ULong)_x4 << 24 ) | \
3558 ( (FT_ULong)_x3 << 16 ) | \
3559 ( (FT_ULong)_x2 << 8 ) | \
3562 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3577 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3581 BYTE devXRatio
, devYRatio
;
3582 USHORT numRecs
, numRatios
;
3583 DWORD result
, offset
= -1;
3587 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3589 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3592 /* FIXME: need the real device aspect ratio */
3596 numRecs
= GET_BE_WORD(hdr
[1]);
3597 numRatios
= GET_BE_WORD(hdr
[2]);
3599 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3600 for(i
= 0; i
< numRatios
; i
++) {
3603 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3604 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3607 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3609 if((ratio
.xRatio
== 0 &&
3610 ratio
.yStartRatio
== 0 &&
3611 ratio
.yEndRatio
== 0) ||
3612 (devXRatio
== ratio
.xRatio
&&
3613 devYRatio
>= ratio
.yStartRatio
&&
3614 devYRatio
<= ratio
.yEndRatio
))
3616 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3617 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3618 offset
= GET_BE_WORD(tmp
);
3624 FIXME("No suitable ratio found\n");
3628 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3630 BYTE startsz
, endsz
;
3633 recs
= GET_BE_WORD(group
.recs
);
3634 startsz
= group
.startsz
;
3635 endsz
= group
.endsz
;
3637 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3639 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3640 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3641 if(result
== GDI_ERROR
) {
3642 FIXME("Failed to retrieve vTable\n");
3647 for(i
= 0; i
< recs
; i
++) {
3648 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3649 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3650 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3652 if(yMax
+ -yMin
== height
) {
3655 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3658 if(yMax
+ -yMin
> height
) {
3661 goto end
; /* failed */
3663 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3664 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3665 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3666 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3672 TRACE("ppem not found for height %d\n", height
);
3676 HeapFree(GetProcessHeap(), 0, vTable
);
3682 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3684 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3685 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3686 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3687 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3688 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3691 static void calc_hash(FONT_DESC
*pfd
)
3693 DWORD hash
= 0, *ptr
, two_chars
;
3697 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3699 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3701 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3703 pwc
= (WCHAR
*)&two_chars
;
3705 *pwc
= toupperW(*pwc
);
3707 *pwc
= toupperW(*pwc
);
3711 hash
^= !pfd
->can_use_bitmap
;
3716 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3721 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3725 fd
.can_use_bitmap
= can_use_bitmap
;
3728 /* try the child list */
3729 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3730 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3731 if(!fontcmp(ret
, &fd
)) {
3732 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3733 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3734 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3735 if(hflist
->hfont
== hfont
)
3741 /* try the in-use list */
3742 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3743 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3744 if(!fontcmp(ret
, &fd
)) {
3745 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3746 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3747 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3748 if(hflist
->hfont
== hfont
)
3751 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3752 hflist
->hfont
= hfont
;
3753 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3758 /* then the unused list */
3759 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3760 while(font_elem_ptr
) {
3761 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3762 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3763 if(!fontcmp(ret
, &fd
)) {
3764 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3765 assert(list_empty(&ret
->hfontlist
));
3766 TRACE("Found %p in unused list\n", ret
);
3767 list_remove(&ret
->entry
);
3768 list_add_head(&gdi_font_list
, &ret
->entry
);
3769 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3770 hflist
->hfont
= hfont
;
3771 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3778 static void add_to_cache(GdiFont
*font
)
3780 static DWORD cache_num
= 1;
3782 font
->cache_num
= cache_num
++;
3783 list_add_head(&gdi_font_list
, &font
->entry
);
3786 /*************************************************************
3787 * create_child_font_list
3789 static BOOL
create_child_font_list(GdiFont
*font
)
3792 SYSTEM_LINKS
*font_link
;
3793 CHILD_FONT
*font_link_entry
, *new_child
;
3797 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3798 font_name
= psub
? psub
->to
.name
: font
->name
;
3799 font_link
= find_font_link(font_name
);
3800 if (font_link
!= NULL
)
3802 TRACE("found entry in system list\n");
3803 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3805 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3806 new_child
->face
= font_link_entry
->face
;
3807 new_child
->font
= NULL
;
3808 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3809 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3814 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3815 * Sans Serif. This is how asian windows get default fallbacks for fonts
3817 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3818 font
->charset
!= OEM_CHARSET
&&
3819 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3821 font_link
= find_font_link(szDefaultFallbackLink
);
3822 if (font_link
!= NULL
)
3824 TRACE("found entry in default fallback list\n");
3825 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3827 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3828 new_child
->face
= font_link_entry
->face
;
3829 new_child
->font
= NULL
;
3830 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3831 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3840 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3842 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3844 if (pFT_Set_Charmap
)
3847 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3849 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3851 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3853 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3855 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3856 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3858 switch (ft_face
->charmaps
[i
]->platform_id
)
3861 cmap_def
= ft_face
->charmaps
[i
];
3863 case 0: /* Apple Unicode */
3864 cmap0
= ft_face
->charmaps
[i
];
3866 case 1: /* Macintosh */
3867 cmap1
= ft_face
->charmaps
[i
];
3870 cmap2
= ft_face
->charmaps
[i
];
3872 case 3: /* Microsoft */
3873 cmap3
= ft_face
->charmaps
[i
];
3878 if (cmap3
) /* prefer Microsoft cmap table */
3879 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3881 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3883 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3885 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3887 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3889 return ft_err
== FT_Err_Ok
;
3892 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3896 /*************************************************************
3899 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
3900 LPCWSTR output
, const DEVMODEW
*devmode
)
3902 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
3904 if (!physdev
) return FALSE
;
3905 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
3910 /*************************************************************
3913 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
3915 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3916 HeapFree( GetProcessHeap(), 0, physdev
);
3921 /*************************************************************
3922 * freetype_SelectFont
3924 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
3926 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3928 Face
*face
, *best
, *best_bitmap
;
3929 Family
*family
, *last_resort_family
;
3930 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
3931 INT height
, width
= 0;
3932 unsigned int score
= 0, new_score
;
3933 signed int diff
= 0, newdiff
;
3934 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
3939 FontSubst
*psub
= NULL
;
3940 DC
*dc
= get_dc_ptr( dev
->hdc
);
3941 const SYSTEM_LINKS
*font_link
;
3943 if (!hfont
) /* notification that the font has been changed by another driver */
3946 physdev
->font
= NULL
;
3947 release_dc_ptr( dc
);
3951 GetObjectW( hfont
, sizeof(lf
), &lf
);
3952 lf
.lfWidth
= abs(lf
.lfWidth
);
3954 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
3956 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3957 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3958 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3961 if(dc
->GraphicsMode
== GM_ADVANCED
)
3963 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3964 /* Try to avoid not necessary glyph transformations */
3965 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3967 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3968 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3969 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3974 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3975 font scaling abilities. */
3976 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3977 dcmat
.eM21
= dcmat
.eM12
= 0;
3978 if (dc
->vport2WorldValid
)
3980 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
3981 lf
.lfOrientation
= -lf
.lfOrientation
;
3982 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
3983 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
3987 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3988 dcmat
.eM21
, dcmat
.eM22
);
3991 EnterCriticalSection( &freetype_cs
);
3993 /* check the cache first */
3994 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3995 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3999 if(list_empty(&font_list
)) /* No fonts installed */
4001 TRACE("No fonts installed\n");
4005 TRACE("not in cache\n");
4008 ret
->font_desc
.matrix
= dcmat
;
4009 ret
->font_desc
.lf
= lf
;
4010 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4011 calc_hash(&ret
->font_desc
);
4012 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4013 hflist
->hfont
= hfont
;
4014 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4016 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4017 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4018 original value lfCharSet. Note this is a special case for
4019 Symbol and doesn't happen at least for "Wingdings*" */
4021 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4022 lf
.lfCharSet
= SYMBOL_CHARSET
;
4024 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4025 switch(lf
.lfCharSet
) {
4026 case DEFAULT_CHARSET
:
4027 csi
.fs
.fsCsb
[0] = 0;
4030 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4031 csi
.fs
.fsCsb
[0] = 0;
4037 if(lf
.lfFaceName
[0] != '\0') {
4038 CHILD_FONT
*font_link_entry
;
4039 LPWSTR FaceName
= lf
.lfFaceName
;
4041 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4044 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4045 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4046 if (psub
->to
.charset
!= -1)
4047 lf
.lfCharSet
= psub
->to
.charset
;
4050 /* We want a match on name and charset or just name if
4051 charset was DEFAULT_CHARSET. If the latter then
4052 we fixup the returned charset later in get_nearest_charset
4053 where we'll either use the charset of the current ansi codepage
4054 or if that's unavailable the first charset that the font supports.
4056 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4057 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4058 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4059 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4061 font_link
= find_font_link(family
->FamilyName
);
4062 face_list
= get_face_list_from_family(family
);
4063 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4064 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4065 if (!(face
->scalable
|| can_use_bitmap
))
4067 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4069 if (font_link
!= NULL
&&
4070 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4072 if (!csi
.fs
.fsCsb
[0])
4078 /* Search by full face name. */
4079 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4080 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4081 face_list
= get_face_list_from_family(family
);
4082 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4083 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4084 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4085 (face
->scalable
|| can_use_bitmap
))
4087 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4089 font_link
= find_font_link(family
->FamilyName
);
4090 if (font_link
!= NULL
&&
4091 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4098 * Try check the SystemLink list first for a replacement font.
4099 * We may find good replacements there.
4101 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4103 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4104 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4106 TRACE("found entry in system list\n");
4107 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4109 const SYSTEM_LINKS
*links
;
4111 face
= font_link_entry
->face
;
4112 if (!(face
->scalable
|| can_use_bitmap
))
4114 family
= face
->family
;
4115 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4117 links
= find_font_link(family
->FamilyName
);
4118 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4125 psub
= NULL
; /* substitution is no more relevant */
4127 /* If requested charset was DEFAULT_CHARSET then try using charset
4128 corresponding to the current ansi codepage */
4129 if (!csi
.fs
.fsCsb
[0])
4132 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4133 FIXME("TCI failed on codepage %d\n", acp
);
4134 csi
.fs
.fsCsb
[0] = 0;
4136 lf
.lfCharSet
= csi
.ciCharset
;
4139 want_vertical
= (lf
.lfFaceName
[0] == '@');
4141 /* Face families are in the top 4 bits of lfPitchAndFamily,
4142 so mask with 0xF0 before testing */
4144 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4145 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4146 strcpyW(lf
.lfFaceName
, defFixed
);
4147 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4148 strcpyW(lf
.lfFaceName
, defSerif
);
4149 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4150 strcpyW(lf
.lfFaceName
, defSans
);
4152 strcpyW(lf
.lfFaceName
, defSans
);
4153 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4154 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4155 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4156 font_link
= find_font_link(family
->FamilyName
);
4157 face_list
= get_face_list_from_family(family
);
4158 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4159 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4160 if (!(face
->scalable
|| can_use_bitmap
))
4162 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4164 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4170 last_resort_family
= NULL
;
4171 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4172 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4173 font_link
= find_font_link(family
->FamilyName
);
4174 face_list
= get_face_list_from_family(family
);
4175 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4176 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4177 if(face
->vertical
== want_vertical
&&
4178 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4179 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4182 if(can_use_bitmap
&& !last_resort_family
)
4183 last_resort_family
= family
;
4188 if(last_resort_family
) {
4189 family
= last_resort_family
;
4190 csi
.fs
.fsCsb
[0] = 0;
4194 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4195 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4196 face_list
= get_face_list_from_family(family
);
4197 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4198 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4199 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4200 csi
.fs
.fsCsb
[0] = 0;
4201 WARN("just using first face for now\n");
4204 if(can_use_bitmap
&& !last_resort_family
)
4205 last_resort_family
= family
;
4208 if(!last_resort_family
) {
4209 FIXME("can't find a single appropriate font - bailing\n");
4215 WARN("could only find a bitmap font - this will probably look awful!\n");
4216 family
= last_resort_family
;
4217 csi
.fs
.fsCsb
[0] = 0;
4220 it
= lf
.lfItalic
? 1 : 0;
4221 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4223 height
= lf
.lfHeight
;
4225 face
= best
= best_bitmap
= NULL
;
4226 font_link
= find_font_link(family
->FamilyName
);
4227 face_list
= get_face_list_from_family(family
);
4228 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4230 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4231 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4236 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4237 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4238 new_score
= (italic
^ it
) + (bold
^ bd
);
4239 if(!best
|| new_score
<= score
)
4241 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4242 italic
, bold
, it
, bd
);
4245 if(best
->scalable
&& score
== 0) break;
4249 newdiff
= height
- (signed int)(best
->size
.height
);
4251 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4252 if(!best_bitmap
|| new_score
< score
||
4253 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4255 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4258 if(score
== 0 && diff
== 0) break;
4265 face
= best
->scalable
? best
: best_bitmap
;
4266 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4267 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4270 height
= lf
.lfHeight
;
4274 if(csi
.fs
.fsCsb
[0]) {
4275 ret
->charset
= lf
.lfCharSet
;
4276 ret
->codepage
= csi
.ciACP
;
4279 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4281 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4282 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4284 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4286 if(!face
->scalable
) {
4287 /* Windows uses integer scaling factors for bitmap fonts */
4288 INT scale
, scaled_height
;
4289 GdiFont
*cachedfont
;
4291 /* FIXME: rotation of bitmap fonts is ignored */
4292 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4294 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4295 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4296 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4297 /* As we changed the matrix, we need to search the cache for the font again,
4298 * otherwise we might explode the cache. */
4299 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4300 TRACE("Found cached font after non-scalable matrix rescale!\n");
4305 calc_hash(&ret
->font_desc
);
4307 if (height
!= 0) height
= diff
;
4308 height
+= face
->size
.height
;
4310 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4311 scaled_height
= scale
* face
->size
.height
;
4312 /* Only jump to the next height if the difference <= 25% original height */
4313 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4314 /* The jump between unscaled and doubled is delayed by 1 */
4315 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4316 ret
->scale_y
= scale
;
4318 width
= face
->size
.x_ppem
>> 6;
4319 height
= face
->size
.y_ppem
>> 6;
4323 TRACE("font scale y: %f\n", ret
->scale_y
);
4325 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4334 ret
->ntmFlags
= face
->ntmFlags
;
4336 if (ret
->charset
== SYMBOL_CHARSET
&&
4337 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4340 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4344 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4347 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4348 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4349 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4350 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4351 create_child_font_list(ret
);
4353 if (face
->vertical
) /* We need to try to load the GSUB table */
4355 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4356 if (length
!= GDI_ERROR
)
4358 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4359 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4360 TRACE("Loaded GSUB table of %i bytes\n",length
);
4364 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4371 physdev
->font
= ret
;
4373 LeaveCriticalSection( &freetype_cs
);
4374 release_dc_ptr( dc
);
4375 return ret
? hfont
: 0;
4378 static void dump_gdi_font_list(void)
4381 struct list
*elem_ptr
;
4383 TRACE("---------- gdiFont Cache ----------\n");
4384 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4385 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4386 TRACE("gdiFont=%p %s %d\n",
4387 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4390 TRACE("---------- Unused gdiFont Cache ----------\n");
4391 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4392 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4393 TRACE("gdiFont=%p %s %d\n",
4394 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4397 TRACE("---------- Child gdiFont Cache ----------\n");
4398 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4399 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4400 TRACE("gdiFont=%p %s %d\n",
4401 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4405 /*************************************************************
4406 * WineEngDestroyFontInstance
4408 * free the gdiFont associated with this handle
4411 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4416 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4420 EnterCriticalSection( &freetype_cs
);
4422 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4424 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4425 while(hfontlist_elem_ptr
) {
4426 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4427 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4428 if(hflist
->hfont
== handle
) {
4429 TRACE("removing child font %p from child list\n", gdiFont
);
4430 list_remove(&gdiFont
->entry
);
4431 LeaveCriticalSection( &freetype_cs
);
4437 TRACE("destroying hfont=%p\n", handle
);
4439 dump_gdi_font_list();
4441 font_elem_ptr
= list_head(&gdi_font_list
);
4442 while(font_elem_ptr
) {
4443 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4444 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4446 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4447 while(hfontlist_elem_ptr
) {
4448 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4449 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4450 if(hflist
->hfont
== handle
) {
4451 list_remove(&hflist
->entry
);
4452 HeapFree(GetProcessHeap(), 0, hflist
);
4456 if(list_empty(&gdiFont
->hfontlist
)) {
4457 TRACE("Moving to Unused list\n");
4458 list_remove(&gdiFont
->entry
);
4459 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4464 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4465 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4466 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4467 while(font_elem_ptr
) {
4468 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4469 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4470 TRACE("freeing %p\n", gdiFont
);
4471 list_remove(&gdiFont
->entry
);
4474 LeaveCriticalSection( &freetype_cs
);
4478 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4485 id
+= IDS_FIRST_SCRIPT
;
4486 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4487 if (!rsrc
) return 0;
4488 hMem
= LoadResource( gdi32_module
, rsrc
);
4489 if (!hMem
) return 0;
4491 p
= LockResource( hMem
);
4493 while (id
--) p
+= *p
+ 1;
4495 i
= min(LF_FACESIZE
- 1, *p
);
4496 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4502 /***************************************************
4503 * create_enum_charset_list
4505 * This function creates charset enumeration list because in DEFAULT_CHARSET
4506 * case, the ANSI codepage's charset takes precedence over other charsets.
4507 * This function works as a filter other than DEFAULT_CHARSET case.
4509 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4514 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4515 csi
.fs
.fsCsb
[0] != 0) {
4516 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4517 list
->element
[n
].charset
= csi
.ciCharset
;
4518 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4521 else { /* charset is DEFAULT_CHARSET or invalid. */
4524 /* Set the current codepage's charset as the first element. */
4526 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4527 csi
.fs
.fsCsb
[0] != 0) {
4528 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4529 list
->element
[n
].charset
= csi
.ciCharset
;
4530 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4534 /* Fill out left elements. */
4535 for (i
= 0; i
< 32; i
++) {
4537 fs
.fsCsb
[0] = 1L << i
;
4539 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4540 continue; /* skip, already added. */
4541 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4542 continue; /* skip, this is an invalid fsCsb bit. */
4544 list
->element
[n
].mask
= fs
.fsCsb
[0];
4545 list
->element
[n
].charset
= csi
.ciCharset
;
4546 load_script_name( i
, list
->element
[n
].name
);
4555 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4556 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4561 if (face
->cached_enum_data
)
4564 *pelf
= face
->cached_enum_data
->elf
;
4565 *pntm
= face
->cached_enum_data
->ntm
;
4566 *ptype
= face
->cached_enum_data
->type
;
4570 font
= alloc_font();
4572 if(face
->scalable
) {
4573 height
= -2048; /* 2048 is the most common em size */
4576 height
= face
->size
.y_ppem
>> 6;
4577 width
= face
->size
.x_ppem
>> 6;
4579 font
->scale_y
= 1.0;
4581 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4587 font
->name
= strdupW(face
->family
->FamilyName
);
4588 font
->ntmFlags
= face
->ntmFlags
;
4590 if (get_outline_text_metrics(font
))
4592 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4594 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4596 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4597 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4599 lstrcpynW(pelf
->elfFullName
,
4600 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4602 lstrcpynW(pelf
->elfStyle
,
4603 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4608 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4610 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4612 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4614 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4616 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4617 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4620 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4621 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4622 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4623 pntm
->ntmFontSig
= face
->fs
;
4625 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4627 pelf
->elfLogFont
.lfEscapement
= 0;
4628 pelf
->elfLogFont
.lfOrientation
= 0;
4629 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4630 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4631 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4632 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4633 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4634 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4635 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4636 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4637 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4638 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4639 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4642 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4643 *ptype
|= TRUETYPE_FONTTYPE
;
4644 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4645 *ptype
|= DEVICE_FONTTYPE
;
4646 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4647 *ptype
|= RASTER_FONTTYPE
;
4649 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4650 if (face
->cached_enum_data
)
4652 face
->cached_enum_data
->elf
= *pelf
;
4653 face
->cached_enum_data
->ntm
= *pntm
;
4654 face
->cached_enum_data
->type
= *ptype
;
4660 static void create_full_name(WCHAR
*full_name
, const WCHAR
*family_name
, const WCHAR
*style_name
)
4662 static const WCHAR spaceW
[] = { ' ', 0 };
4664 strcpyW(full_name
, family_name
);
4665 strcatW(full_name
, spaceW
);
4666 strcatW(full_name
, style_name
);
4669 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4671 const struct list
*face_list
, *face_elem_ptr
;
4673 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4675 face_list
= get_face_list_from_family(family
);
4676 LIST_FOR_EACH(face_elem_ptr
, face_list
)
4678 WCHAR full_family_name
[LF_FULLFACESIZE
];
4679 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4681 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4683 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4684 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4688 create_full_name(full_family_name
, family
->FamilyName
, face
->StyleName
);
4689 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4695 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
4697 WCHAR full_family_name
[LF_FULLFACESIZE
];
4699 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
4701 if (strlenW(family_name
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4703 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4704 debugstr_w(family_name
), debugstr_w(face
->StyleName
));
4708 create_full_name(full_family_name
, family_name
, face
->StyleName
);
4709 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4712 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
4713 FONTENUMPROCW proc
, LPARAM lparam
)
4716 NEWTEXTMETRICEXW ntm
;
4720 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4721 for(i
= 0; i
< list
->total
; i
++) {
4722 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4723 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4724 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4725 i
= list
->total
; /* break out of loop after enumeration */
4726 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4729 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4730 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4731 if (!elf
.elfScript
[0])
4732 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4734 /* Font Replacement */
4735 if (family
!= face
->family
)
4737 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
4738 create_full_name(elf
.elfFullName
, family
->FamilyName
, face
->StyleName
);
4740 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4741 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4742 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4743 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4744 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4745 ntm
.ntmTm
.ntmFlags
);
4746 /* release section before callback (FIXME) */
4747 LeaveCriticalSection( &freetype_cs
);
4748 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4749 EnterCriticalSection( &freetype_cs
);
4754 /*************************************************************
4755 * freetype_EnumFonts
4757 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4761 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4763 struct enum_charset_list enum_charsets
;
4767 lf
.lfCharSet
= DEFAULT_CHARSET
;
4768 lf
.lfPitchAndFamily
= 0;
4769 lf
.lfFaceName
[0] = 0;
4773 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4775 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4778 EnterCriticalSection( &freetype_cs
);
4779 if(plf
->lfFaceName
[0]) {
4781 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4784 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4785 debugstr_w(psub
->to
.name
));
4787 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4791 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4792 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4793 if(family_matches(family
, plf
)) {
4794 face_list
= get_face_list_from_family(family
);
4795 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4796 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4797 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
4798 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4803 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4804 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4805 face_list
= get_face_list_from_family(family
);
4806 face_elem_ptr
= list_head(face_list
);
4807 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4808 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4811 LeaveCriticalSection( &freetype_cs
);
4815 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4817 pt
->x
.value
= vec
->x
>> 6;
4818 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4819 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4820 pt
->y
.value
= vec
->y
>> 6;
4821 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4822 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4826 /***************************************************
4827 * According to the MSDN documentation on WideCharToMultiByte,
4828 * certain codepages cannot set the default_used parameter.
4829 * This returns TRUE if the codepage can set that parameter, false else
4830 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4832 static BOOL
codepage_sets_default_used(UINT codepage
)
4846 * GSUB Table handling functions
4849 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4851 const GSUB_CoverageFormat1
* cf1
;
4855 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4857 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4859 TRACE("Coverage Format 1, %i glyphs\n",count
);
4860 for (i
= 0; i
< count
; i
++)
4861 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4865 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4867 const GSUB_CoverageFormat2
* cf2
;
4870 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4872 count
= GET_BE_WORD(cf2
->RangeCount
);
4873 TRACE("Coverage Format 2, %i ranges\n",count
);
4874 for (i
= 0; i
< count
; i
++)
4876 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4878 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4879 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4881 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4882 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4888 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4893 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4895 const GSUB_ScriptList
*script
;
4896 const GSUB_Script
*deflt
= NULL
;
4898 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4900 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4901 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4903 const GSUB_Script
*scr
;
4906 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4907 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4909 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4911 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4917 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4921 const GSUB_LangSys
*Lang
;
4923 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4925 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4927 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4928 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4930 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4933 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4936 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4942 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4945 const GSUB_FeatureList
*feature
;
4946 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4948 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4949 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4951 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4952 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4954 const GSUB_Feature
*feat
;
4955 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4962 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4966 const GSUB_LookupList
*lookup
;
4967 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4969 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4970 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4972 const GSUB_LookupTable
*look
;
4973 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4974 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4975 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4976 if (GET_BE_WORD(look
->LookupType
) != 1)
4977 FIXME("We only handle SubType 1\n");
4982 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4984 const GSUB_SingleSubstFormat1
*ssf1
;
4985 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4986 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4987 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4989 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4990 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4991 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4993 TRACE(" Glyph 0x%x ->",glyph
);
4994 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4995 TRACE(" 0x%x\n",glyph
);
5000 const GSUB_SingleSubstFormat2
*ssf2
;
5004 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5005 offset
= GET_BE_WORD(ssf1
->Coverage
);
5006 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5007 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5008 TRACE(" Coverage index %i\n",index
);
5011 TRACE(" Glyph is 0x%x ->",glyph
);
5012 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5013 TRACE("0x%x\n",glyph
);
5022 static const char* get_opentype_script(const GdiFont
*font
)
5025 * I am not sure if this is the correct way to generate our script tag
5028 switch (font
->charset
)
5030 case ANSI_CHARSET
: return "latn";
5031 case BALTIC_CHARSET
: return "latn"; /* ?? */
5032 case CHINESEBIG5_CHARSET
: return "hani";
5033 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5034 case GB2312_CHARSET
: return "hani";
5035 case GREEK_CHARSET
: return "grek";
5036 case HANGUL_CHARSET
: return "hang";
5037 case RUSSIAN_CHARSET
: return "cyrl";
5038 case SHIFTJIS_CHARSET
: return "kana";
5039 case TURKISH_CHARSET
: return "latn"; /* ?? */
5040 case VIETNAMESE_CHARSET
: return "latn";
5041 case JOHAB_CHARSET
: return "latn"; /* ?? */
5042 case ARABIC_CHARSET
: return "arab";
5043 case HEBREW_CHARSET
: return "hebr";
5044 case THAI_CHARSET
: return "thai";
5045 default: return "latn";
5049 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5051 const GSUB_Header
*header
;
5052 const GSUB_Script
*script
;
5053 const GSUB_LangSys
*language
;
5054 const GSUB_Feature
*feature
;
5056 if (!font
->GSUB_Table
)
5059 header
= font
->GSUB_Table
;
5061 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5064 TRACE("Script not found\n");
5067 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5070 TRACE("Language not found\n");
5073 feature
= GSUB_get_feature(header
, language
, "vrt2");
5075 feature
= GSUB_get_feature(header
, language
, "vert");
5078 TRACE("vrt2/vert feature not found\n");
5081 return GSUB_apply_feature(header
, feature
, glyph
);
5084 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5088 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5089 WCHAR wc
= (WCHAR
)glyph
;
5091 BOOL
*default_used_pointer
;
5094 default_used_pointer
= NULL
;
5095 default_used
= FALSE
;
5096 if (codepage_sets_default_used(font
->codepage
))
5097 default_used_pointer
= &default_used
;
5098 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5101 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5102 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5106 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5108 if (glyph
< 0x100) glyph
+= 0xf000;
5109 /* there is a number of old pre-Unicode "broken" TTFs, which
5110 do have symbols at U+00XX instead of U+f0XX */
5111 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5112 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5114 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5119 /*************************************************************
5120 * freetype_GetGlyphIndices
5122 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5124 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5127 BOOL got_default
= FALSE
;
5131 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5132 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5135 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5137 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5142 EnterCriticalSection( &freetype_cs
);
5144 for(i
= 0; i
< count
; i
++)
5146 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5151 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5153 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5154 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5159 get_text_metrics(physdev
->font
, &textm
);
5160 default_char
= textm
.tmDefaultChar
;
5164 pgi
[i
] = default_char
;
5167 LeaveCriticalSection( &freetype_cs
);
5171 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5173 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5174 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5177 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5179 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5180 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5183 static inline BYTE
get_max_level( UINT format
)
5187 case GGO_GRAY2_BITMAP
: return 4;
5188 case GGO_GRAY4_BITMAP
: return 16;
5189 case GGO_GRAY8_BITMAP
: return 64;
5194 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5196 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5197 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5200 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5201 FT_Face ft_face
= incoming_font
->ft_face
;
5202 GdiFont
*font
= incoming_font
;
5203 FT_UInt glyph_index
;
5204 DWORD width
, height
, pitch
, needed
= 0;
5205 FT_Bitmap ft_bitmap
;
5207 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5209 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5210 double widthRatio
= 1.0;
5211 FT_Matrix transMat
= identityMat
;
5212 FT_Matrix transMatUnrotated
;
5213 BOOL needsTransform
= FALSE
;
5214 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5215 UINT original_index
;
5217 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5218 buflen
, buf
, lpmat
);
5220 TRACE("font transform %f %f %f %f\n",
5221 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5222 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5224 if(format
& GGO_GLYPH_INDEX
) {
5225 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5226 original_index
= glyph
;
5227 format
&= ~GGO_GLYPH_INDEX
;
5229 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5230 ft_face
= font
->ft_face
;
5231 original_index
= glyph_index
;
5234 if(format
& GGO_UNHINTED
) {
5235 load_flags
|= FT_LOAD_NO_HINTING
;
5236 format
&= ~GGO_UNHINTED
;
5239 /* tategaki never appears to happen to lower glyph index */
5240 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5243 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5244 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5245 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5246 font
->gmsize
* sizeof(GM
*));
5248 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5249 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5251 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5252 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5253 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5254 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5255 return 1; /* FIXME */
5259 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5260 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5262 /* Scaling factor */
5267 get_text_metrics(font
, &tm
);
5269 widthRatio
= (double)font
->aveWidth
;
5270 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5273 widthRatio
= font
->scale_y
;
5275 /* Scaling transform */
5276 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5279 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5282 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5284 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5285 needsTransform
= TRUE
;
5288 /* Slant transform */
5289 if (font
->fake_italic
) {
5292 slantMat
.xx
= (1 << 16);
5293 slantMat
.xy
= ((1 << 16) >> 2);
5295 slantMat
.yy
= (1 << 16);
5296 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5297 needsTransform
= TRUE
;
5300 /* Rotation transform */
5301 transMatUnrotated
= transMat
;
5302 if(font
->orientation
&& !tategaki
) {
5303 FT_Matrix rotationMat
;
5305 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5306 pFT_Vector_Unit(&vecAngle
, angle
);
5307 rotationMat
.xx
= vecAngle
.x
;
5308 rotationMat
.xy
= -vecAngle
.y
;
5309 rotationMat
.yx
= -rotationMat
.xy
;
5310 rotationMat
.yy
= rotationMat
.xx
;
5312 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5313 needsTransform
= TRUE
;
5316 /* World transform */
5317 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5320 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5321 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5322 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5323 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5324 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5325 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5326 needsTransform
= TRUE
;
5329 /* Extra transformation specified by caller */
5330 if (!is_identity_MAT2(lpmat
))
5333 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5334 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5335 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5336 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5337 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5338 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5339 needsTransform
= TRUE
;
5342 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5343 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5344 format
== GGO_GRAY8_BITMAP
))
5346 load_flags
|= FT_LOAD_NO_BITMAP
;
5349 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5352 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5356 if(!needsTransform
) {
5357 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5358 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5359 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5361 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5362 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5363 ft_face
->glyph
->metrics
.height
) & -64;
5364 lpgm
->gmCellIncX
= adv
;
5365 lpgm
->gmCellIncY
= 0;
5372 for(xc
= 0; xc
< 2; xc
++) {
5373 for(yc
= 0; yc
< 2; yc
++) {
5374 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5375 xc
* ft_face
->glyph
->metrics
.width
);
5376 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5377 yc
* ft_face
->glyph
->metrics
.height
;
5378 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5379 pFT_Vector_Transform(&vec
, &transMat
);
5380 if(xc
== 0 && yc
== 0) {
5381 left
= right
= vec
.x
;
5382 top
= bottom
= vec
.y
;
5384 if(vec
.x
< left
) left
= vec
.x
;
5385 else if(vec
.x
> right
) right
= vec
.x
;
5386 if(vec
.y
< bottom
) bottom
= vec
.y
;
5387 else if(vec
.y
> top
) top
= vec
.y
;
5392 right
= (right
+ 63) & -64;
5393 bottom
= bottom
& -64;
5394 top
= (top
+ 63) & -64;
5396 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5397 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5399 pFT_Vector_Transform(&vec
, &transMat
);
5400 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5401 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5403 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5405 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5406 adv
= (vec
.x
+63) >> 6;
5410 bbx
= (right
- left
) >> 6;
5411 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5412 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5413 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5414 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5416 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5417 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5418 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5420 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5421 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5423 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5424 FONT_GM(font
,original_index
)->adv
= adv
;
5425 FONT_GM(font
,original_index
)->lsb
= lsb
;
5426 FONT_GM(font
,original_index
)->bbx
= bbx
;
5427 FONT_GM(font
,original_index
)->init
= TRUE
;
5430 if(format
== GGO_METRICS
)
5432 return 1; /* FIXME */
5435 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5436 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5438 TRACE("loaded a bitmap\n");
5444 width
= lpgm
->gmBlackBoxX
;
5445 height
= lpgm
->gmBlackBoxY
;
5446 pitch
= ((width
+ 31) >> 5) << 2;
5447 needed
= pitch
* height
;
5449 if(!buf
|| !buflen
) break;
5451 switch(ft_face
->glyph
->format
) {
5452 case ft_glyph_format_bitmap
:
5454 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5455 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5456 INT h
= ft_face
->glyph
->bitmap
.rows
;
5458 memcpy(dst
, src
, w
);
5459 src
+= ft_face
->glyph
->bitmap
.pitch
;
5465 case ft_glyph_format_outline
:
5466 ft_bitmap
.width
= width
;
5467 ft_bitmap
.rows
= height
;
5468 ft_bitmap
.pitch
= pitch
;
5469 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5470 ft_bitmap
.buffer
= buf
;
5473 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5475 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5477 /* Note: FreeType will only set 'black' bits for us. */
5478 memset(buf
, 0, needed
);
5479 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5483 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5488 case GGO_GRAY2_BITMAP
:
5489 case GGO_GRAY4_BITMAP
:
5490 case GGO_GRAY8_BITMAP
:
5491 case WINE_GGO_GRAY16_BITMAP
:
5493 unsigned int max_level
, row
, col
;
5496 width
= lpgm
->gmBlackBoxX
;
5497 height
= lpgm
->gmBlackBoxY
;
5498 pitch
= (width
+ 3) / 4 * 4;
5499 needed
= pitch
* height
;
5501 if(!buf
|| !buflen
) break;
5503 max_level
= get_max_level( format
);
5505 switch(ft_face
->glyph
->format
) {
5506 case ft_glyph_format_bitmap
:
5508 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5509 INT h
= ft_face
->glyph
->bitmap
.rows
;
5511 memset( buf
, 0, needed
);
5513 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5514 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5515 src
+= ft_face
->glyph
->bitmap
.pitch
;
5520 case ft_glyph_format_outline
:
5522 ft_bitmap
.width
= width
;
5523 ft_bitmap
.rows
= height
;
5524 ft_bitmap
.pitch
= pitch
;
5525 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5526 ft_bitmap
.buffer
= buf
;
5529 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5531 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5533 memset(ft_bitmap
.buffer
, 0, buflen
);
5535 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5537 if (max_level
!= 255)
5539 for (row
= 0, start
= buf
; row
< height
; row
++)
5541 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5542 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5550 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5556 case WINE_GGO_HRGB_BITMAP
:
5557 case WINE_GGO_HBGR_BITMAP
:
5558 case WINE_GGO_VRGB_BITMAP
:
5559 case WINE_GGO_VBGR_BITMAP
:
5560 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5562 switch (ft_face
->glyph
->format
)
5564 case FT_GLYPH_FORMAT_BITMAP
:
5569 width
= lpgm
->gmBlackBoxX
;
5570 height
= lpgm
->gmBlackBoxY
;
5572 needed
= pitch
* height
;
5574 if (!buf
|| !buflen
) break;
5576 memset(buf
, 0, buflen
);
5578 src
= ft_face
->glyph
->bitmap
.buffer
;
5579 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5581 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5584 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5586 if ( src
[x
/ 8] & masks
[x
% 8] )
5587 ((unsigned int *)dst
)[x
] = ~0u;
5596 case FT_GLYPH_FORMAT_OUTLINE
:
5600 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5601 INT x_shift
, y_shift
;
5603 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5604 FT_Render_Mode render_mode
=
5605 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5606 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5608 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5610 if ( render_mode
== FT_RENDER_MODE_LCD
)
5612 lpgm
->gmBlackBoxX
+= 2;
5613 lpgm
->gmptGlyphOrigin
.x
-= 1;
5617 lpgm
->gmBlackBoxY
+= 2;
5618 lpgm
->gmptGlyphOrigin
.y
+= 1;
5622 width
= lpgm
->gmBlackBoxX
;
5623 height
= lpgm
->gmBlackBoxY
;
5625 needed
= pitch
* height
;
5627 if (!buf
|| !buflen
) break;
5629 memset(buf
, 0, buflen
);
5631 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5633 if ( needsTransform
)
5634 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5636 if ( pFT_Library_SetLcdFilter
)
5637 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5638 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5640 src
= ft_face
->glyph
->bitmap
.buffer
;
5641 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5642 src_width
= ft_face
->glyph
->bitmap
.width
;
5643 src_height
= ft_face
->glyph
->bitmap
.rows
;
5645 if ( render_mode
== FT_RENDER_MODE_LCD
)
5653 rgb_interval
= src_pitch
;
5658 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5659 if ( x_shift
< 0 ) x_shift
= 0;
5660 if ( x_shift
+ (src_width
/ hmul
) > width
)
5661 x_shift
= width
- (src_width
/ hmul
);
5663 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5664 if ( y_shift
< 0 ) y_shift
= 0;
5665 if ( y_shift
+ (src_height
/ vmul
) > height
)
5666 y_shift
= height
- (src_height
/ vmul
);
5668 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5669 while ( src_height
)
5671 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5675 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5676 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5677 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5678 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5682 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5683 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5684 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5685 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5688 src
+= src_pitch
* vmul
;
5697 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5709 int contour
, point
= 0, first_pt
;
5710 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5711 TTPOLYGONHEADER
*pph
;
5713 DWORD pph_start
, cpfx
, type
;
5715 if(buflen
== 0) buf
= NULL
;
5717 if (needsTransform
&& buf
) {
5718 pFT_Outline_Transform(outline
, &transMat
);
5721 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5723 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5726 pph
->dwType
= TT_POLYGON_TYPE
;
5727 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5729 needed
+= sizeof(*pph
);
5731 while(point
<= outline
->contours
[contour
]) {
5732 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5733 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5734 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5738 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5741 } while(point
<= outline
->contours
[contour
] &&
5742 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5743 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5744 /* At the end of a contour Windows adds the start point, but
5746 if(point
> outline
->contours
[contour
] &&
5747 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5749 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5751 } else if(point
<= outline
->contours
[contour
] &&
5752 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5753 /* add closing pt for bezier */
5755 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5763 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5766 pph
->cb
= needed
- pph_start
;
5772 /* Convert the quadratic Beziers to cubic Beziers.
5773 The parametric eqn for a cubic Bezier is, from PLRM:
5774 r(t) = at^3 + bt^2 + ct + r0
5775 with the control points:
5780 A quadratic Bezier has the form:
5781 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5783 So equating powers of t leads to:
5784 r1 = 2/3 p1 + 1/3 p0
5785 r2 = 2/3 p1 + 1/3 p2
5786 and of course r0 = p0, r3 = p2
5789 int contour
, point
= 0, first_pt
;
5790 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5791 TTPOLYGONHEADER
*pph
;
5793 DWORD pph_start
, cpfx
, type
;
5794 FT_Vector cubic_control
[4];
5795 if(buflen
== 0) buf
= NULL
;
5797 if (needsTransform
&& buf
) {
5798 pFT_Outline_Transform(outline
, &transMat
);
5801 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5803 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5806 pph
->dwType
= TT_POLYGON_TYPE
;
5807 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5809 needed
+= sizeof(*pph
);
5811 while(point
<= outline
->contours
[contour
]) {
5812 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5813 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5814 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5817 if(type
== TT_PRIM_LINE
) {
5819 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5823 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5826 /* FIXME: Possible optimization in endpoint calculation
5827 if there are two consecutive curves */
5828 cubic_control
[0] = outline
->points
[point
-1];
5829 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5830 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5831 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5832 cubic_control
[0].x
>>= 1;
5833 cubic_control
[0].y
>>= 1;
5835 if(point
+1 > outline
->contours
[contour
])
5836 cubic_control
[3] = outline
->points
[first_pt
];
5838 cubic_control
[3] = outline
->points
[point
+1];
5839 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5840 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5841 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5842 cubic_control
[3].x
>>= 1;
5843 cubic_control
[3].y
>>= 1;
5846 /* r1 = 1/3 p0 + 2/3 p1
5847 r2 = 1/3 p2 + 2/3 p1 */
5848 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5849 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5850 cubic_control
[2] = cubic_control
[1];
5851 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5852 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5853 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5854 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5856 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5857 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5858 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5863 } while(point
<= outline
->contours
[contour
] &&
5864 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5865 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5866 /* At the end of a contour Windows adds the start point,
5867 but only for Beziers and we've already done that.
5869 if(point
<= outline
->contours
[contour
] &&
5870 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5871 /* This is the closing pt of a bezier, but we've already
5872 added it, so just inc point and carry on */
5879 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5882 pph
->cb
= needed
- pph_start
;
5888 FIXME("Unsupported format %d\n", format
);
5894 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5896 FT_Face ft_face
= font
->ft_face
;
5897 FT_WinFNT_HeaderRec winfnt_header
;
5898 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5899 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5900 font
->potm
->otmSize
= size
;
5902 #define TM font->potm->otmTextMetrics
5903 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5905 TM
.tmHeight
= winfnt_header
.pixel_height
;
5906 TM
.tmAscent
= winfnt_header
.ascent
;
5907 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5908 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5909 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5910 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5911 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5912 TM
.tmWeight
= winfnt_header
.weight
;
5914 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5915 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5916 TM
.tmFirstChar
= winfnt_header
.first_char
;
5917 TM
.tmLastChar
= winfnt_header
.last_char
;
5918 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5919 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5920 TM
.tmItalic
= winfnt_header
.italic
;
5921 TM
.tmUnderlined
= font
->underline
;
5922 TM
.tmStruckOut
= font
->strikeout
;
5923 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5924 TM
.tmCharSet
= winfnt_header
.charset
;
5928 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5929 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5930 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5931 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5932 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5933 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5934 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5935 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5937 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5938 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5940 TM
.tmLastChar
= 255;
5941 TM
.tmDefaultChar
= 32;
5942 TM
.tmBreakChar
= 32;
5943 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5944 TM
.tmUnderlined
= font
->underline
;
5945 TM
.tmStruckOut
= font
->strikeout
;
5946 /* NB inverted meaning of TMPF_FIXED_PITCH */
5947 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5948 TM
.tmCharSet
= font
->charset
;
5956 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5958 double scale_x
, scale_y
;
5962 scale_x
= (double)font
->aveWidth
;
5963 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5966 scale_x
= font
->scale_y
;
5968 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5969 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5971 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5972 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5974 SCALE_Y(ptm
->tmHeight
);
5975 SCALE_Y(ptm
->tmAscent
);
5976 SCALE_Y(ptm
->tmDescent
);
5977 SCALE_Y(ptm
->tmInternalLeading
);
5978 SCALE_Y(ptm
->tmExternalLeading
);
5979 SCALE_Y(ptm
->tmOverhang
);
5981 SCALE_X(ptm
->tmAveCharWidth
);
5982 SCALE_X(ptm
->tmMaxCharWidth
);
5988 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5990 double scale_x
, scale_y
;
5994 scale_x
= (double)font
->aveWidth
;
5995 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5998 scale_x
= font
->scale_y
;
6000 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6001 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6003 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6005 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6006 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6008 SCALE_Y(potm
->otmAscent
);
6009 SCALE_Y(potm
->otmDescent
);
6010 SCALE_Y(potm
->otmLineGap
);
6011 SCALE_Y(potm
->otmsCapEmHeight
);
6012 SCALE_Y(potm
->otmsXHeight
);
6013 SCALE_Y(potm
->otmrcFontBox
.top
);
6014 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6015 SCALE_X(potm
->otmrcFontBox
.left
);
6016 SCALE_X(potm
->otmrcFontBox
.right
);
6017 SCALE_Y(potm
->otmMacAscent
);
6018 SCALE_Y(potm
->otmMacDescent
);
6019 SCALE_Y(potm
->otmMacLineGap
);
6020 SCALE_X(potm
->otmptSubscriptSize
.x
);
6021 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6022 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6023 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6024 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6025 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6026 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6027 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6028 SCALE_Y(potm
->otmsStrikeoutSize
);
6029 SCALE_Y(potm
->otmsStrikeoutPosition
);
6030 SCALE_Y(potm
->otmsUnderscoreSize
);
6031 SCALE_Y(potm
->otmsUnderscorePosition
);
6037 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6041 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6043 /* Make sure that the font has sane width/height ratio */
6046 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6048 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6053 *ptm
= font
->potm
->otmTextMetrics
;
6054 scale_font_metrics(font
, ptm
);
6058 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6062 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6064 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6070 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6073 FT_Face ft_face
= font
->ft_face
;
6074 UINT needed
, lenfam
, lensty
;
6076 TT_HoriHeader
*pHori
;
6077 TT_Postscript
*pPost
;
6078 FT_Fixed x_scale
, y_scale
;
6079 WCHAR
*family_nameW
, *style_nameW
;
6080 static const WCHAR spaceW
[] = {' ', '\0'};
6082 INT ascent
, descent
;
6084 TRACE("font=%p\n", font
);
6086 if(!FT_IS_SCALABLE(ft_face
))
6089 needed
= sizeof(*font
->potm
);
6091 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6092 family_nameW
= strdupW(font
->name
);
6094 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6096 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6097 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6098 style_nameW
, lensty
/sizeof(WCHAR
));
6100 /* These names should be read from the TT name table */
6102 /* length of otmpFamilyName */
6105 /* length of otmpFaceName */
6106 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6107 needed
+= lenfam
; /* just the family name */
6109 needed
+= lenfam
+ lensty
; /* family + " " + style */
6112 /* length of otmpStyleName */
6115 /* length of otmpFullName */
6116 needed
+= lenfam
+ lensty
;
6119 x_scale
= ft_face
->size
->metrics
.x_scale
;
6120 y_scale
= ft_face
->size
->metrics
.y_scale
;
6122 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6124 FIXME("Can't find OS/2 table - not TT font?\n");
6128 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6130 FIXME("Can't find HHEA table - not TT font?\n");
6134 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6136 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",
6137 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6138 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6139 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6140 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6141 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6143 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6144 font
->potm
->otmSize
= needed
;
6146 #define TM font->potm->otmTextMetrics
6148 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6149 ascent
= pHori
->Ascender
;
6150 descent
= -pHori
->Descender
;
6152 ascent
= pOS2
->usWinAscent
;
6153 descent
= pOS2
->usWinDescent
;
6157 TM
.tmAscent
= font
->yMax
;
6158 TM
.tmDescent
= -font
->yMin
;
6159 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6161 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6162 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6163 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6164 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6167 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6170 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6172 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6173 ((ascent
+ descent
) -
6174 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6176 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6177 if (TM
.tmAveCharWidth
== 0) {
6178 TM
.tmAveCharWidth
= 1;
6180 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6181 TM
.tmWeight
= FW_REGULAR
;
6182 if (font
->fake_bold
)
6183 TM
.tmWeight
= FW_BOLD
;
6186 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6188 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6189 TM
.tmWeight
= pOS2
->usWeightClass
;
6191 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6192 TM
.tmWeight
= pOS2
->usWeightClass
;
6195 TM
.tmDigitizedAspectX
= 300;
6196 TM
.tmDigitizedAspectY
= 300;
6197 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6198 * symbol range to 0 - f0ff
6201 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6206 case 1257: /* Baltic */
6207 TM
.tmLastChar
= 0xf8fd;
6210 TM
.tmLastChar
= 0xf0ff;
6212 TM
.tmBreakChar
= 0x20;
6213 TM
.tmDefaultChar
= 0x1f;
6217 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6218 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6220 if(pOS2
->usFirstCharIndex
<= 1)
6221 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6222 else if (pOS2
->usFirstCharIndex
> 0xff)
6223 TM
.tmBreakChar
= 0x20;
6225 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6226 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6228 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6229 TM
.tmUnderlined
= font
->underline
;
6230 TM
.tmStruckOut
= font
->strikeout
;
6232 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6233 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6234 (pOS2
->version
== 0xFFFFU
||
6235 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6236 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6238 TM
.tmPitchAndFamily
= 0;
6240 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6242 case PAN_FAMILY_SCRIPT
:
6243 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6246 case PAN_FAMILY_DECORATIVE
:
6247 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6252 case PAN_FAMILY_TEXT_DISPLAY
:
6253 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6254 /* which is clearly not what the panose spec says. */
6256 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6257 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6258 TM
.tmPitchAndFamily
= FF_MODERN
;
6261 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6266 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6269 case PAN_SERIF_COVE
:
6270 case PAN_SERIF_OBTUSE_COVE
:
6271 case PAN_SERIF_SQUARE_COVE
:
6272 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6273 case PAN_SERIF_SQUARE
:
6274 case PAN_SERIF_THIN
:
6275 case PAN_SERIF_BONE
:
6276 case PAN_SERIF_EXAGGERATED
:
6277 case PAN_SERIF_TRIANGLE
:
6278 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6281 case PAN_SERIF_NORMAL_SANS
:
6282 case PAN_SERIF_OBTUSE_SANS
:
6283 case PAN_SERIF_PERP_SANS
:
6284 case PAN_SERIF_FLARED
:
6285 case PAN_SERIF_ROUNDED
:
6286 TM
.tmPitchAndFamily
|= FF_SWISS
;
6293 if(FT_IS_SCALABLE(ft_face
))
6294 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6296 if(FT_IS_SFNT(ft_face
))
6298 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6299 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6301 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6304 TM
.tmCharSet
= font
->charset
;
6306 font
->potm
->otmFiller
= 0;
6307 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6308 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6309 font
->potm
->otmfsType
= pOS2
->fsType
;
6310 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6311 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6312 font
->potm
->otmItalicAngle
= 0; /* POST table */
6313 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6314 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6315 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6316 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6317 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6318 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6319 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6320 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6321 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6322 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6323 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6324 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6325 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6326 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6327 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6328 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6329 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6330 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6331 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6332 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6333 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6334 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6335 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6336 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6338 font
->potm
->otmsUnderscoreSize
= 0;
6339 font
->potm
->otmsUnderscorePosition
= 0;
6341 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6342 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6346 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6347 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6348 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6349 strcpyW((WCHAR
*)cp
, family_nameW
);
6351 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6352 strcpyW((WCHAR
*)cp
, style_nameW
);
6354 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6355 strcpyW((WCHAR
*)cp
, family_nameW
);
6356 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6357 strcatW((WCHAR
*)cp
, spaceW
);
6358 strcatW((WCHAR
*)cp
, style_nameW
);
6359 cp
+= lenfam
+ lensty
;
6362 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6363 strcpyW((WCHAR
*)cp
, family_nameW
);
6364 strcatW((WCHAR
*)cp
, spaceW
);
6365 strcatW((WCHAR
*)cp
, style_nameW
);
6369 HeapFree(GetProcessHeap(), 0, style_nameW
);
6370 HeapFree(GetProcessHeap(), 0, family_nameW
);
6374 /*************************************************************
6375 * freetype_GetGlyphOutline
6377 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6378 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6380 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6385 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6386 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6390 EnterCriticalSection( &freetype_cs
);
6391 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6392 LeaveCriticalSection( &freetype_cs
);
6396 /*************************************************************
6397 * freetype_GetTextMetrics
6399 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6401 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6406 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6407 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6411 EnterCriticalSection( &freetype_cs
);
6412 ret
= get_text_metrics( physdev
->font
, metrics
);
6413 LeaveCriticalSection( &freetype_cs
);
6417 /*************************************************************
6418 * freetype_GetOutlineTextMetrics
6420 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6422 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6427 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6428 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6431 TRACE("font=%p\n", physdev
->font
);
6433 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6436 EnterCriticalSection( &freetype_cs
);
6438 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6440 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6442 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6443 scale_outline_font_metrics(physdev
->font
, potm
);
6445 ret
= physdev
->font
->potm
->otmSize
;
6447 LeaveCriticalSection( &freetype_cs
);
6451 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6453 HFONTLIST
*hfontlist
;
6454 child
->font
= alloc_font();
6455 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6456 if(!child
->font
->ft_face
)
6458 free_font(child
->font
);
6463 child
->font
->font_desc
= font
->font_desc
;
6464 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6465 child
->font
->orientation
= font
->orientation
;
6466 child
->font
->scale_y
= font
->scale_y
;
6467 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6468 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6469 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6470 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6471 child
->font
->base_font
= font
;
6472 list_add_head(&child_font_list
, &child
->font
->entry
);
6473 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6477 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6480 CHILD_FONT
*child_font
;
6483 font
= font
->base_font
;
6485 *linked_font
= font
;
6487 if((*glyph
= get_glyph_index(font
, c
)))
6489 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6493 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6495 if(!child_font
->font
)
6496 if(!load_child_font(font
, child_font
))
6499 if(!child_font
->font
->ft_face
)
6501 g
= get_glyph_index(child_font
->font
, c
);
6502 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6506 *linked_font
= child_font
->font
;
6513 /*************************************************************
6514 * freetype_GetCharWidth
6516 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6518 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6521 FT_UInt glyph_index
;
6522 GdiFont
*linked_font
;
6523 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6527 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6528 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6531 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6534 EnterCriticalSection( &freetype_cs
);
6535 for(c
= firstChar
; c
<= lastChar
; c
++) {
6536 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6537 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6538 &gm
, 0, NULL
, &identity
);
6539 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6541 LeaveCriticalSection( &freetype_cs
);
6545 /*************************************************************
6546 * freetype_GetCharABCWidths
6548 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6550 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6553 FT_UInt glyph_index
;
6554 GdiFont
*linked_font
;
6555 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6559 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6560 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6563 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6566 EnterCriticalSection( &freetype_cs
);
6568 for(c
= firstChar
; c
<= lastChar
; c
++) {
6569 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6570 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6571 &gm
, 0, NULL
, &identity
);
6572 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6573 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6574 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6575 FONT_GM(linked_font
,glyph_index
)->bbx
;
6577 LeaveCriticalSection( &freetype_cs
);
6581 /*************************************************************
6582 * freetype_GetCharABCWidthsI
6584 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6586 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6589 FT_UInt glyph_index
;
6590 GdiFont
*linked_font
;
6591 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6595 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6596 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6599 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6603 EnterCriticalSection( &freetype_cs
);
6605 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6607 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6608 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6609 &gm
, 0, NULL
, &identity
);
6610 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6611 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6612 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6613 - FONT_GM(linked_font
,c
)->bbx
;
6616 for(c
= 0; c
< count
; c
++) {
6617 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6618 &gm
, 0, NULL
, &identity
);
6619 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6620 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6621 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6622 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6625 LeaveCriticalSection( &freetype_cs
);
6629 /*************************************************************
6630 * freetype_GetTextExtentExPoint
6632 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6633 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6635 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6640 FT_UInt glyph_index
;
6641 GdiFont
*linked_font
;
6642 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6646 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6647 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6650 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6653 EnterCriticalSection( &freetype_cs
);
6656 get_text_metrics( physdev
->font
, &tm
);
6657 size
->cy
= tm
.tmHeight
;
6659 for(idx
= 0; idx
< count
; idx
++) {
6660 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6661 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6662 &gm
, 0, NULL
, &identity
);
6663 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6665 if (! pnfit
|| ext
<= max_ext
) {
6675 LeaveCriticalSection( &freetype_cs
);
6676 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6680 /*************************************************************
6681 * freetype_GetTextExtentExPointI
6683 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6684 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6686 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6691 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6695 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6696 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6699 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6702 EnterCriticalSection( &freetype_cs
);
6705 get_text_metrics(physdev
->font
, &tm
);
6706 size
->cy
= tm
.tmHeight
;
6708 for(idx
= 0; idx
< count
; idx
++) {
6709 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6710 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6712 if (! pnfit
|| ext
<= max_ext
) {
6722 LeaveCriticalSection( &freetype_cs
);
6723 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6727 /*************************************************************
6728 * freetype_GetFontData
6730 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6732 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6736 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6737 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6740 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6741 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6742 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6744 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6747 /*************************************************************
6748 * freetype_GetTextFace
6750 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6753 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6757 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6758 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6761 n
= strlenW(physdev
->font
->name
) + 1;
6764 lstrcpynW(str
, physdev
->font
->name
, count
);
6770 /*************************************************************
6771 * freetype_GetTextCharsetInfo
6773 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6775 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6779 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6780 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6782 if (fs
) *fs
= physdev
->font
->fs
;
6783 return physdev
->font
->charset
;
6786 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6788 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6789 struct list
*first_hfont
;
6793 EnterCriticalSection( &freetype_cs
);
6794 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6795 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6796 if(font
== linked_font
)
6797 *new_hfont
= dc
->hFont
;
6800 first_hfont
= list_head(&linked_font
->hfontlist
);
6801 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6803 LeaveCriticalSection( &freetype_cs
);
6807 /* Retrieve a list of supported Unicode ranges for a given font.
6808 * Can be called with NULL gs to calculate the buffer size. Returns
6809 * the number of ranges found.
6811 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6813 DWORD num_ranges
= 0;
6815 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6818 FT_ULong char_code
, char_code_prev
;
6821 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6823 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6824 face
->num_glyphs
, glyph_code
, char_code
);
6826 if (!glyph_code
) return 0;
6830 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6831 gs
->ranges
[0].cGlyphs
= 0;
6832 gs
->cGlyphsSupported
= 0;
6838 if (char_code
< char_code_prev
)
6840 ERR("expected increasing char code from FT_Get_Next_Char\n");
6843 if (char_code
- char_code_prev
> 1)
6848 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6849 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6850 gs
->cGlyphsSupported
++;
6855 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6856 gs
->cGlyphsSupported
++;
6858 char_code_prev
= char_code
;
6859 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6863 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6868 /*************************************************************
6869 * freetype_GetFontUnicodeRanges
6871 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6873 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6874 DWORD size
, num_ranges
;
6878 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6879 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6882 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6883 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6886 glyphset
->cbThis
= size
;
6887 glyphset
->cRanges
= num_ranges
;
6888 glyphset
->flAccel
= 0;
6893 /*************************************************************
6894 * freetype_FontIsLinked
6896 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6898 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6903 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6904 return dev
->funcs
->pFontIsLinked( dev
);
6908 EnterCriticalSection( &freetype_cs
);
6909 ret
= !list_empty(&physdev
->font
->child_fonts
);
6910 LeaveCriticalSection( &freetype_cs
);
6914 static BOOL
is_hinting_enabled(void)
6916 /* Use the >= 2.2.0 function if available */
6917 if(pFT_Get_TrueType_Engine_Type
)
6919 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6920 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6922 #ifdef FT_DRIVER_HAS_HINTER
6927 /* otherwise if we've been compiled with < 2.2.0 headers
6928 use the internal macro */
6929 mod
= pFT_Get_Module(library
, "truetype");
6930 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6938 static BOOL
is_subpixel_rendering_enabled( void )
6940 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6941 return pFT_Library_SetLcdFilter
&&
6942 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6948 /*************************************************************************
6949 * GetRasterizerCaps (GDI32.@)
6951 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6953 static int hinting
= -1;
6954 static int subpixel
= -1;
6958 hinting
= is_hinting_enabled();
6959 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6962 if ( subpixel
== -1 )
6964 subpixel
= is_subpixel_rendering_enabled();
6965 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6968 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6969 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6971 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6972 lprs
->nLanguageID
= 0;
6976 /*************************************************************
6977 * freetype_GdiRealizationInfo
6979 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
6981 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6982 realization_info_t
*info
= ptr
;
6986 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
6987 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
6990 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
6993 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
6996 info
->cache_num
= physdev
->font
->cache_num
;
6997 info
->unknown2
= -1;
7001 /*************************************************************************
7002 * Kerning support for TrueType fonts
7004 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7006 struct TT_kern_table
7012 struct TT_kern_subtable
7021 USHORT horizontal
: 1;
7023 USHORT cross_stream
: 1;
7024 USHORT override
: 1;
7025 USHORT reserved1
: 4;
7031 struct TT_format0_kern_subtable
7035 USHORT entrySelector
;
7046 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7047 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7048 const USHORT
*glyph_to_char
,
7049 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7052 const struct TT_kern_pair
*tt_kern_pair
;
7054 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7056 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7058 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7059 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7060 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7062 if (!kern_pair
|| !cPairs
)
7065 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7067 nPairs
= min(nPairs
, cPairs
);
7069 for (i
= 0; i
< nPairs
; i
++)
7071 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7072 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7073 /* this algorithm appears to better match what Windows does */
7074 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7075 if (kern_pair
->iKernAmount
< 0)
7077 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7078 kern_pair
->iKernAmount
-= font
->ppem
;
7080 else if (kern_pair
->iKernAmount
> 0)
7082 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7083 kern_pair
->iKernAmount
+= font
->ppem
;
7085 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7087 TRACE("left %u right %u value %d\n",
7088 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7092 TRACE("copied %u entries\n", nPairs
);
7096 /*************************************************************
7097 * freetype_GetKerningPairs
7099 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7103 const struct TT_kern_table
*tt_kern_table
;
7104 const struct TT_kern_subtable
*tt_kern_subtable
;
7106 USHORT
*glyph_to_char
;
7108 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7110 if (!(font
= physdev
->font
))
7112 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7113 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7117 EnterCriticalSection( &freetype_cs
);
7118 if (font
->total_kern_pairs
!= (DWORD
)-1)
7120 if (cPairs
&& kern_pair
)
7122 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7123 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7125 else cPairs
= font
->total_kern_pairs
;
7127 LeaveCriticalSection( &freetype_cs
);
7131 font
->total_kern_pairs
= 0;
7133 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7135 if (length
== GDI_ERROR
)
7137 TRACE("no kerning data in the font\n");
7138 LeaveCriticalSection( &freetype_cs
);
7142 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7145 WARN("Out of memory\n");
7146 LeaveCriticalSection( &freetype_cs
);
7150 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7152 /* build a glyph index to char code map */
7153 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7156 WARN("Out of memory allocating a glyph index to char code map\n");
7157 HeapFree(GetProcessHeap(), 0, buf
);
7158 LeaveCriticalSection( &freetype_cs
);
7162 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7168 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7170 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7171 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7175 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7177 /* FIXME: This doesn't match what Windows does: it does some fancy
7178 * things with duplicate glyph index to char code mappings, while
7179 * we just avoid overriding existing entries.
7181 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7182 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7184 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7191 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7192 for (n
= 0; n
<= 65535; n
++)
7193 glyph_to_char
[n
] = (USHORT
)n
;
7196 tt_kern_table
= buf
;
7197 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7198 TRACE("version %u, nTables %u\n",
7199 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7201 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7203 for (i
= 0; i
< nTables
; i
++)
7205 struct TT_kern_subtable tt_kern_subtable_copy
;
7207 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7208 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7209 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7211 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7212 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7213 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7215 /* According to the TrueType specification this is the only format
7216 * that will be properly interpreted by Windows and OS/2
7218 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7220 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7222 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7223 glyph_to_char
, NULL
, 0);
7224 font
->total_kern_pairs
+= new_chunk
;
7226 if (!font
->kern_pairs
)
7227 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7228 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7230 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7231 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7233 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7234 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7237 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7239 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7242 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7243 HeapFree(GetProcessHeap(), 0, buf
);
7245 if (cPairs
&& kern_pair
)
7247 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7248 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7250 else cPairs
= font
->total_kern_pairs
;
7252 LeaveCriticalSection( &freetype_cs
);
7256 static const struct gdi_dc_funcs freetype_funcs
=
7258 NULL
, /* pAbortDoc */
7259 NULL
, /* pAbortPath */
7260 NULL
, /* pAlphaBlend */
7261 NULL
, /* pAngleArc */
7264 NULL
, /* pBeginPath */
7265 NULL
, /* pBlendImage */
7266 NULL
, /* pChoosePixelFormat */
7268 NULL
, /* pCloseFigure */
7269 NULL
, /* pCopyBitmap */
7270 NULL
, /* pCreateBitmap */
7271 NULL
, /* pCreateCompatibleDC */
7272 freetype_CreateDC
, /* pCreateDC */
7273 NULL
, /* pDeleteBitmap */
7274 freetype_DeleteDC
, /* pDeleteDC */
7275 NULL
, /* pDeleteObject */
7276 NULL
, /* pDescribePixelFormat */
7277 NULL
, /* pDeviceCapabilities */
7278 NULL
, /* pEllipse */
7280 NULL
, /* pEndPage */
7281 NULL
, /* pEndPath */
7282 freetype_EnumFonts
, /* pEnumFonts */
7283 NULL
, /* pEnumICMProfiles */
7284 NULL
, /* pExcludeClipRect */
7285 NULL
, /* pExtDeviceMode */
7286 NULL
, /* pExtEscape */
7287 NULL
, /* pExtFloodFill */
7288 NULL
, /* pExtSelectClipRgn */
7289 NULL
, /* pExtTextOut */
7290 NULL
, /* pFillPath */
7291 NULL
, /* pFillRgn */
7292 NULL
, /* pFlattenPath */
7293 freetype_FontIsLinked
, /* pFontIsLinked */
7294 NULL
, /* pFrameRgn */
7295 NULL
, /* pGdiComment */
7296 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7297 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7298 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7299 freetype_GetCharWidth
, /* pGetCharWidth */
7300 NULL
, /* pGetDeviceCaps */
7301 NULL
, /* pGetDeviceGammaRamp */
7302 freetype_GetFontData
, /* pGetFontData */
7303 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7304 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7305 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7306 NULL
, /* pGetICMProfile */
7307 NULL
, /* pGetImage */
7308 freetype_GetKerningPairs
, /* pGetKerningPairs */
7309 NULL
, /* pGetNearestColor */
7310 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7311 NULL
, /* pGetPixel */
7312 NULL
, /* pGetPixelFormat */
7313 NULL
, /* pGetSystemPaletteEntries */
7314 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7315 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7316 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7317 freetype_GetTextFace
, /* pGetTextFace */
7318 freetype_GetTextMetrics
, /* pGetTextMetrics */
7319 NULL
, /* pGradientFill */
7320 NULL
, /* pIntersectClipRect */
7321 NULL
, /* pInvertRgn */
7323 NULL
, /* pModifyWorldTransform */
7325 NULL
, /* pOffsetClipRgn */
7326 NULL
, /* pOffsetViewportOrg */
7327 NULL
, /* pOffsetWindowOrg */
7328 NULL
, /* pPaintRgn */
7331 NULL
, /* pPolyBezier */
7332 NULL
, /* pPolyBezierTo */
7333 NULL
, /* pPolyDraw */
7334 NULL
, /* pPolyPolygon */
7335 NULL
, /* pPolyPolyline */
7336 NULL
, /* pPolygon */
7337 NULL
, /* pPolyline */
7338 NULL
, /* pPolylineTo */
7339 NULL
, /* pPutImage */
7340 NULL
, /* pRealizeDefaultPalette */
7341 NULL
, /* pRealizePalette */
7342 NULL
, /* pRectangle */
7343 NULL
, /* pResetDC */
7344 NULL
, /* pRestoreDC */
7345 NULL
, /* pRoundRect */
7347 NULL
, /* pScaleViewportExt */
7348 NULL
, /* pScaleWindowExt */
7349 NULL
, /* pSelectBitmap */
7350 NULL
, /* pSelectBrush */
7351 NULL
, /* pSelectClipPath */
7352 freetype_SelectFont
, /* pSelectFont */
7353 NULL
, /* pSelectPalette */
7354 NULL
, /* pSelectPen */
7355 NULL
, /* pSetArcDirection */
7356 NULL
, /* pSetBkColor */
7357 NULL
, /* pSetBkMode */
7358 NULL
, /* pSetDCBrushColor */
7359 NULL
, /* pSetDCPenColor */
7360 NULL
, /* pSetDIBColorTable */
7361 NULL
, /* pSetDIBitsToDevice */
7362 NULL
, /* pSetDeviceClipping */
7363 NULL
, /* pSetDeviceGammaRamp */
7364 NULL
, /* pSetLayout */
7365 NULL
, /* pSetMapMode */
7366 NULL
, /* pSetMapperFlags */
7367 NULL
, /* pSetPixel */
7368 NULL
, /* pSetPixelFormat */
7369 NULL
, /* pSetPolyFillMode */
7370 NULL
, /* pSetROP2 */
7371 NULL
, /* pSetRelAbs */
7372 NULL
, /* pSetStretchBltMode */
7373 NULL
, /* pSetTextAlign */
7374 NULL
, /* pSetTextCharacterExtra */
7375 NULL
, /* pSetTextColor */
7376 NULL
, /* pSetTextJustification */
7377 NULL
, /* pSetViewportExt */
7378 NULL
, /* pSetViewportOrg */
7379 NULL
, /* pSetWindowExt */
7380 NULL
, /* pSetWindowOrg */
7381 NULL
, /* pSetWorldTransform */
7382 NULL
, /* pStartDoc */
7383 NULL
, /* pStartPage */
7384 NULL
, /* pStretchBlt */
7385 NULL
, /* pStretchDIBits */
7386 NULL
, /* pStrokeAndFillPath */
7387 NULL
, /* pStrokePath */
7388 NULL
, /* pSwapBuffers */
7389 NULL
, /* pUnrealizePalette */
7390 NULL
, /* pWidenPath */
7391 /* OpenGL not supported */
7394 #else /* HAVE_FREETYPE */
7396 /*************************************************************************/
7398 BOOL
WineEngInit(void)
7402 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7407 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7409 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7413 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7415 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7419 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7421 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7425 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7430 /*************************************************************************
7431 * GetRasterizerCaps (GDI32.@)
7433 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7435 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7437 lprs
->nLanguageID
= 0;
7441 #endif /* HAVE_FREETYPE */