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 #define ADDFONT_EXTERNAL_FONT 0x01
1500 #define ADDFONT_FORCE_BITMAP 0x02
1501 #define ADDFONT_ADD_TO_CACHE 0x04
1503 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
)
1512 WCHAR
*english_family
, *localised_family
;
1514 struct list
*face_elem_ptr
;
1515 FT_WinFNT_HeaderRec winfnt_header
;
1516 int internal_leading
;
1518 My_FT_Bitmap_Size
*size
= NULL
;
1521 if(!FT_IS_SCALABLE(ft_face
))
1522 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1524 english_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1525 if (!english_family
)
1526 english_family
= towstr(CP_ACP
, ft_face
->family_name
);
1528 localised_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID());
1529 if (localised_family
&& !strcmpiW(localised_family
, english_family
))
1531 HeapFree(GetProcessHeap(), 0, localised_family
);
1532 localised_family
= NULL
;
1537 english_family
= prepend_at(english_family
);
1538 localised_family
= prepend_at(localised_family
);
1541 family
= find_family_from_name(localised_family
? localised_family
: english_family
);
1543 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1544 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1545 family
->EnglishName
= localised_family
? strdupW(english_family
) : NULL
;
1546 list_init(&family
->faces
);
1547 family
->replacement
= &family
->faces
;
1548 list_add_tail(&font_list
, &family
->entry
);
1550 if(localised_family
) {
1551 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1552 subst
->from
.name
= strdupW(english_family
);
1553 subst
->from
.charset
= -1;
1554 subst
->to
.name
= strdupW(localised_family
);
1555 subst
->to
.charset
= -1;
1556 add_font_subst(&font_subst_list
, subst
, 0);
1559 HeapFree(GetProcessHeap(), 0, localised_family
);
1560 HeapFree(GetProcessHeap(), 0, english_family
);
1562 StyleW
= towstr(CP_ACP
, ft_face
->style_name
);
1564 internal_leading
= 0;
1565 memset(&fs
, 0, sizeof(fs
));
1567 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1569 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1570 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1571 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1572 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1573 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1574 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1575 if(pOS2
->version
== 0) {
1578 if(pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1579 fs
.fsCsb
[0] |= FS_LATIN1
;
1581 fs
.fsCsb
[0] |= FS_SYMBOL
;
1584 else if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1586 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1587 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1588 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1590 internal_leading
= winfnt_header
.internal_leading
;
1593 pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
);
1594 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1595 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1596 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1597 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1598 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1599 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1600 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1602 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1603 TRACE("Original font is newer so skipping this one\n");
1604 HeapFree(GetProcessHeap(), 0, StyleW
);
1607 TRACE("Replacing original with this one\n");
1608 list_remove(&face
->entry
);
1609 HeapFree(GetProcessHeap(), 0, face
->file
);
1610 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1611 HeapFree(GetProcessHeap(), 0, face
->FullName
);
1612 HeapFree(GetProcessHeap(), 0, face
);
1617 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1618 face
->cached_enum_data
= NULL
;
1619 face
->StyleName
= StyleW
;
1620 face
->FullName
= get_face_name(ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1623 face
->file
= strdupA(file
);
1624 face
->font_data_ptr
= NULL
;
1625 face
->font_data_size
= 0;
1630 face
->font_data_ptr
= font_data_ptr
;
1631 face
->font_data_size
= font_data_size
;
1633 face
->face_index
= face_index
;
1635 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1636 face
->ntmFlags
|= NTM_ITALIC
;
1637 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1638 face
->ntmFlags
|= NTM_BOLD
;
1639 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1640 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1641 face
->family
= family
;
1642 face
->vertical
= vertical
;
1643 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1646 if(FT_IS_SCALABLE(ft_face
)) {
1647 memset(&face
->size
, 0, sizeof(face
->size
));
1648 face
->scalable
= TRUE
;
1650 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1651 size
->height
, size
->width
, size
->size
>> 6,
1652 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1653 face
->size
.height
= size
->height
;
1654 face
->size
.width
= size
->width
;
1655 face
->size
.size
= size
->size
;
1656 face
->size
.x_ppem
= size
->x_ppem
;
1657 face
->size
.y_ppem
= size
->y_ppem
;
1658 face
->size
.internal_leading
= internal_leading
;
1659 face
->scalable
= FALSE
;
1662 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1664 if (!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1666 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1667 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1670 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1671 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1672 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1673 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1675 if(face
->fs
.fsCsb
[0] == 0)
1679 /* let's see if we can find any interesting cmaps */
1680 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1681 switch(ft_face
->charmaps
[i
]->encoding
) {
1682 case FT_ENCODING_UNICODE
:
1683 case FT_ENCODING_APPLE_ROMAN
:
1684 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1686 case FT_ENCODING_MS_SYMBOL
:
1687 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1695 if(flags
& ADDFONT_ADD_TO_CACHE
)
1696 add_face_to_cache(face
);
1698 AddFaceToFamily(face
, family
);
1700 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1702 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1703 debugstr_w(StyleW
));
1706 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1710 TT_Header
*pHeader
= NULL
;
1712 FT_Long face_index
= 0, num_faces
;
1715 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1716 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1718 #ifdef HAVE_CARBON_CARBON_H
1721 char **mac_list
= expand_mac_font(file
);
1724 BOOL had_one
= FALSE
;
1726 for(cursor
= mac_list
; *cursor
; cursor
++)
1729 AddFontToList(*cursor
, NULL
, 0, flags
);
1730 HeapFree(GetProcessHeap(), 0, *cursor
);
1732 HeapFree(GetProcessHeap(), 0, mac_list
);
1737 #endif /* HAVE_CARBON_CARBON_H */
1742 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1743 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1746 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1747 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1751 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1755 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*/
1756 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1757 pFT_Done_Face(ft_face
);
1761 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1762 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1763 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1764 pFT_Done_Face(ft_face
);
1768 if(FT_IS_SFNT(ft_face
))
1770 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1771 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1772 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1774 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1775 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1776 pFT_Done_Face(ft_face
);
1780 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1781 we don't want to load these. */
1782 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1786 if(!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1788 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1789 pFT_Done_Face(ft_face
);
1795 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1796 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1797 pFT_Done_Face(ft_face
);
1801 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1803 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1804 pFT_Done_Face(ft_face
);
1808 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1811 if (FT_HAS_VERTICAL(ft_face
))
1813 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1817 num_faces
= ft_face
->num_faces
;
1818 pFT_Done_Face(ft_face
);
1819 } while(num_faces
> ++face_index
);
1823 static void DumpFontList(void)
1827 struct list
*family_elem_ptr
, *face_elem_ptr
;
1829 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1830 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1831 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1832 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1833 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1834 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1836 TRACE(" %d", face
->size
.height
);
1843 /***********************************************************
1844 * The replacement list is a way to map an entire font
1845 * family onto another family. For example adding
1847 * [HKCU\Software\Wine\Fonts\Replacements]
1848 * "Wingdings"="Winedings"
1850 * would enumerate the Winedings font both as Winedings and
1851 * Wingdings. However if a real Wingdings font is present the
1852 * replacement does not take place.
1855 static void LoadReplaceList(void)
1858 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1863 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1864 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1866 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1867 &valuelen
, &datalen
, NULL
, NULL
);
1869 valuelen
++; /* returned value doesn't include room for '\0' */
1870 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1871 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1875 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1876 &dlen
) == ERROR_SUCCESS
) {
1877 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1878 /* "NewName"="Oldname" */
1879 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1881 if(!find_family_from_any_name(value
))
1883 Family
* const family
= find_family_from_any_name(data
);
1886 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
1887 if (new_family
!= NULL
)
1889 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
1890 new_family
->FamilyName
= strdupW(value
);
1891 new_family
->EnglishName
= NULL
;
1892 list_init(&new_family
->faces
);
1893 new_family
->replacement
= &family
->faces
;
1894 list_add_tail(&font_list
, &new_family
->entry
);
1899 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
1904 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
1906 /* reset dlen and vlen */
1910 HeapFree(GetProcessHeap(), 0, data
);
1911 HeapFree(GetProcessHeap(), 0, value
);
1916 static const WCHAR
*font_links_list
[] =
1918 Lucida_Sans_Unicode
,
1919 Microsoft_Sans_Serif
,
1923 static const struct font_links_defaults_list
1925 /* Keyed off substitution for "MS Shell Dlg" */
1926 const WCHAR
*shelldlg
;
1927 /* Maximum of four substitutes, plus terminating NULL pointer */
1928 const WCHAR
*substitutes
[5];
1929 } font_links_defaults_list
[] =
1931 /* Non East-Asian */
1932 { Tahoma
, /* FIXME unverified ordering */
1933 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
1935 /* Below lists are courtesy of
1936 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1940 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
1942 /* Chinese Simplified */
1944 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
1948 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
1950 /* Chinese Traditional */
1952 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
1957 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
1959 SYSTEM_LINKS
*font_link
;
1961 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1963 if(!strcmpiW(font_link
->font_name
, name
))
1970 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
1982 SYSTEM_LINKS
*font_link
;
1984 psub
= get_font_subst(&font_subst_list
, name
, -1);
1985 /* Don't store fonts that are only substitutes for other fonts */
1988 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
1992 font_link
= find_font_link(name
);
1993 if (font_link
== NULL
)
1995 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1996 font_link
->font_name
= strdupW(name
);
1997 list_init(&font_link
->links
);
1998 list_add_tail(&system_links
, &font_link
->entry
);
2001 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2002 for (i
= 0; values
[i
] != NULL
; i
++)
2004 const struct list
*face_list
;
2005 CHILD_FONT
*child_font
;
2008 if (!strcmpiW(name
,value
))
2010 psub
= get_font_subst(&font_subst_list
, value
, -1);
2012 value
= psub
->to
.name
;
2013 family
= find_family_from_name(value
);
2017 /* Use first extant filename for this Family */
2018 face_list
= get_face_list_from_family(family
);
2019 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2023 file
= strrchr(face
->file
, '/');
2032 fileW
= towstr(CP_UNIXCP
, file
);
2034 face
= find_face_from_filename(fileW
, value
);
2037 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2041 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2042 child_font
->face
= face
;
2043 child_font
->font
= NULL
;
2044 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2045 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2046 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2047 list_add_tail(&font_link
->links
, &child_font
->entry
);
2049 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2050 HeapFree(GetProcessHeap(), 0, fileW
);
2056 /*************************************************************
2059 static BOOL
init_system_links(void)
2063 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2064 WCHAR
*value
, *data
;
2065 WCHAR
*entry
, *next
;
2066 SYSTEM_LINKS
*font_link
, *system_font_link
;
2067 CHILD_FONT
*child_font
;
2068 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2069 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2070 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2075 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2077 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2078 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2079 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2080 val_len
= max_val
+ 1;
2081 data_len
= max_data
;
2083 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2085 psub
= get_font_subst(&font_subst_list
, value
, -1);
2086 /* Don't store fonts that are only substitutes for other fonts */
2089 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2092 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2093 font_link
->font_name
= strdupW(value
);
2094 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2095 list_init(&font_link
->links
);
2096 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2099 CHILD_FONT
*child_font
;
2101 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2103 next
= entry
+ strlenW(entry
) + 1;
2105 face_name
= strchrW(entry
, ',');
2109 while(isspaceW(*face_name
))
2112 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2114 face_name
= psub
->to
.name
;
2116 face
= find_face_from_filename(entry
, face_name
);
2119 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2123 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2124 child_font
->face
= face
;
2125 child_font
->font
= NULL
;
2126 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2127 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2128 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2129 list_add_tail(&font_link
->links
, &child_font
->entry
);
2131 list_add_tail(&system_links
, &font_link
->entry
);
2133 val_len
= max_val
+ 1;
2134 data_len
= max_data
;
2137 HeapFree(GetProcessHeap(), 0, value
);
2138 HeapFree(GetProcessHeap(), 0, data
);
2143 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2145 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2149 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2151 const FontSubst
*psub2
;
2152 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2154 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2156 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2157 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2159 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2160 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2162 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2164 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2170 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2173 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2174 system_font_link
->font_name
= strdupW(System
);
2175 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2176 list_init(&system_font_link
->links
);
2178 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2181 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2182 child_font
->face
= face
;
2183 child_font
->font
= NULL
;
2184 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2185 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2186 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2187 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2189 font_link
= find_font_link(Tahoma
);
2190 if (font_link
!= NULL
)
2192 CHILD_FONT
*font_link_entry
;
2193 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2195 CHILD_FONT
*new_child
;
2196 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2197 new_child
->face
= font_link_entry
->face
;
2198 new_child
->font
= NULL
;
2199 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2200 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2201 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2204 list_add_tail(&system_links
, &system_font_link
->entry
);
2208 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2211 struct dirent
*dent
;
2212 char path
[MAX_PATH
];
2214 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2216 dir
= opendir(dirname
);
2218 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2221 while((dent
= readdir(dir
)) != NULL
) {
2222 struct stat statbuf
;
2224 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2227 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2229 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2231 if(stat(path
, &statbuf
) == -1)
2233 WARN("Can't stat %s\n", debugstr_a(path
));
2236 if(S_ISDIR(statbuf
.st_mode
))
2237 ReadFontDir(path
, external_fonts
);
2240 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2241 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2242 AddFontToList(path
, NULL
, 0, addfont_flags
);
2249 static void load_fontconfig_fonts(void)
2251 #ifdef SONAME_LIBFONTCONFIG
2252 void *fc_handle
= NULL
;
2261 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2263 TRACE("Wine cannot find the fontconfig library (%s).\n",
2264 SONAME_LIBFONTCONFIG
);
2267 #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;}
2268 LOAD_FUNCPTR(FcConfigGetCurrent
);
2269 LOAD_FUNCPTR(FcFontList
);
2270 LOAD_FUNCPTR(FcFontSetDestroy
);
2271 LOAD_FUNCPTR(FcInit
);
2272 LOAD_FUNCPTR(FcObjectSetAdd
);
2273 LOAD_FUNCPTR(FcObjectSetCreate
);
2274 LOAD_FUNCPTR(FcObjectSetDestroy
);
2275 LOAD_FUNCPTR(FcPatternCreate
);
2276 LOAD_FUNCPTR(FcPatternDestroy
);
2277 LOAD_FUNCPTR(FcPatternGetBool
);
2278 LOAD_FUNCPTR(FcPatternGetString
);
2281 if(!pFcInit()) return;
2283 config
= pFcConfigGetCurrent();
2284 pat
= pFcPatternCreate();
2285 os
= pFcObjectSetCreate();
2286 pFcObjectSetAdd(os
, FC_FILE
);
2287 pFcObjectSetAdd(os
, FC_SCALABLE
);
2288 fontset
= pFcFontList(config
, pat
, os
);
2289 if(!fontset
) return;
2290 for(i
= 0; i
< fontset
->nfont
; i
++) {
2293 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2295 TRACE("fontconfig: %s\n", file
);
2297 /* We're just interested in OT/TT fonts for now, so this hack just
2298 picks up the scalable fonts without extensions .pf[ab] to save time
2299 loading every other font */
2301 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2303 TRACE("not scalable\n");
2307 len
= strlen( file
);
2308 if(len
< 4) continue;
2309 ext
= &file
[ len
- 3 ];
2310 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2311 AddFontToList(file
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2313 pFcFontSetDestroy(fontset
);
2314 pFcObjectSetDestroy(os
);
2315 pFcPatternDestroy(pat
);
2321 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2324 const char *data_dir
= wine_get_data_dir();
2326 if (!data_dir
) data_dir
= wine_get_build_dir();
2333 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2335 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2337 strcpy(unix_name
, data_dir
);
2338 strcat(unix_name
, "/fonts/");
2340 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2342 EnterCriticalSection( &freetype_cs
);
2343 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2344 LeaveCriticalSection( &freetype_cs
);
2345 HeapFree(GetProcessHeap(), 0, unix_name
);
2350 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2352 static const WCHAR slashW
[] = {'\\','\0'};
2354 WCHAR windowsdir
[MAX_PATH
];
2357 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2358 strcatW(windowsdir
, fontsW
);
2359 strcatW(windowsdir
, slashW
);
2360 strcatW(windowsdir
, file
);
2361 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2362 EnterCriticalSection( &freetype_cs
);
2363 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2364 LeaveCriticalSection( &freetype_cs
);
2365 HeapFree(GetProcessHeap(), 0, unixname
);
2370 static void load_system_fonts(void)
2373 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2374 const WCHAR
* const *value
;
2376 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2379 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2380 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2381 strcatW(windowsdir
, fontsW
);
2382 for(value
= SystemFontValues
; *value
; value
++) {
2383 dlen
= sizeof(data
);
2384 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2388 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2389 if((unixname
= wine_get_unix_file_name(pathW
))) {
2390 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2391 HeapFree(GetProcessHeap(), 0, unixname
);
2394 load_font_from_data_dir(data
);
2401 /*************************************************************
2403 * This adds registry entries for any externally loaded fonts
2404 * (fonts from fontconfig or FontDirs). It also deletes entries
2405 * of no longer existing fonts.
2408 static void update_reg_entries(void)
2410 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2415 struct list
*family_elem_ptr
, *face_elem_ptr
;
2417 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2418 static const WCHAR spaceW
[] = {' ', '\0'};
2421 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2422 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2423 ERR("Can't create Windows font reg key\n");
2427 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2428 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2429 ERR("Can't create Windows font reg key\n");
2433 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2434 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2435 ERR("Can't create external font reg key\n");
2439 /* enumerate the fonts and add external ones to the two keys */
2441 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2442 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2443 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2444 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2445 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2446 if(!face
->external
) continue;
2448 if (!(face
->ntmFlags
& NTM_REGULAR
))
2449 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2450 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2451 strcpyW(valueW
, family
->FamilyName
);
2452 if(len
!= len_fam
) {
2453 strcatW(valueW
, spaceW
);
2454 strcatW(valueW
, face
->StyleName
);
2456 strcatW(valueW
, TrueType
);
2458 file
= wine_get_dos_file_name(face
->file
);
2460 len
= strlenW(file
) + 1;
2463 if((path
= strrchr(face
->file
, '/')) == NULL
)
2467 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2469 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2470 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2472 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2473 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2474 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2476 HeapFree(GetProcessHeap(), 0, file
);
2477 HeapFree(GetProcessHeap(), 0, valueW
);
2481 if(external_key
) RegCloseKey(external_key
);
2482 if(win9x_key
) RegCloseKey(win9x_key
);
2483 if(winnt_key
) RegCloseKey(winnt_key
);
2487 static void delete_external_font_keys(void)
2489 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2490 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2494 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2495 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2496 ERR("Can't create Windows font reg key\n");
2500 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2501 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2502 ERR("Can't create Windows font reg key\n");
2506 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2507 ERR("Can't create external font reg key\n");
2511 /* Delete all external fonts added last time */
2513 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2514 &valuelen
, &datalen
, NULL
, NULL
);
2515 valuelen
++; /* returned value doesn't include room for '\0' */
2516 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2517 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2519 dlen
= datalen
* sizeof(WCHAR
);
2522 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2523 &dlen
) == ERROR_SUCCESS
) {
2525 RegDeleteValueW(winnt_key
, valueW
);
2526 RegDeleteValueW(win9x_key
, valueW
);
2527 /* reset dlen and vlen */
2531 HeapFree(GetProcessHeap(), 0, data
);
2532 HeapFree(GetProcessHeap(), 0, valueW
);
2534 /* Delete the old external fonts key */
2535 RegCloseKey(external_key
);
2536 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2539 if(win9x_key
) RegCloseKey(win9x_key
);
2540 if(winnt_key
) RegCloseKey(winnt_key
);
2543 /*************************************************************
2544 * WineEngAddFontResourceEx
2547 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2553 if (ft_handle
) /* do it only if we have freetype up and running */
2558 FIXME("Ignoring flags %x\n", flags
);
2560 if((unixname
= wine_get_unix_file_name(file
)))
2562 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2564 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2565 EnterCriticalSection( &freetype_cs
);
2566 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2567 LeaveCriticalSection( &freetype_cs
);
2568 HeapFree(GetProcessHeap(), 0, unixname
);
2570 if (!ret
&& !strchrW(file
, '\\')) {
2571 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2572 ret
= load_font_from_winfonts_dir(file
);
2574 /* Try in datadir/fonts (or builddir/fonts),
2575 * needed for Magic the Gathering Online
2577 ret
= load_font_from_data_dir(file
);
2584 /*************************************************************
2585 * WineEngAddFontMemResourceEx
2588 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2592 if (ft_handle
) /* do it only if we have freetype up and running */
2594 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2596 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2597 memcpy(pFontCopy
, pbFont
, cbFont
);
2599 EnterCriticalSection( &freetype_cs
);
2600 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2601 LeaveCriticalSection( &freetype_cs
);
2605 TRACE("AddFontToList failed\n");
2606 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2609 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2610 * For now return something unique but quite random
2612 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2613 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2620 /*************************************************************
2621 * WineEngRemoveFontResourceEx
2624 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2627 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2631 static const struct nls_update_font_list
2633 UINT ansi_cp
, oem_cp
;
2634 const char *oem
, *fixed
, *system
;
2635 const char *courier
, *serif
, *small
, *sserif
;
2636 /* these are for font substitutes */
2637 const char *shelldlg
, *tmsrmn
;
2638 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2642 const char *from
, *to
;
2643 } arial_0
, courier_new_0
, times_new_roman_0
;
2644 } nls_update_font_list
[] =
2646 /* Latin 1 (United States) */
2647 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2648 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2649 "Tahoma","Times New Roman",
2650 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2653 /* Latin 1 (Multilingual) */
2654 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2655 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2656 "Tahoma","Times New Roman", /* FIXME unverified */
2657 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2660 /* Eastern Europe */
2661 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2662 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2663 "Tahoma","Times New Roman", /* FIXME unverified */
2664 "Fixedsys,238", "System,238",
2665 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2666 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2667 { "Arial CE,0", "Arial,238" },
2668 { "Courier New CE,0", "Courier New,238" },
2669 { "Times New Roman CE,0", "Times New Roman,238" }
2672 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2673 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2674 "Tahoma","Times New Roman", /* FIXME unverified */
2675 "Fixedsys,204", "System,204",
2676 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2677 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2678 { "Arial Cyr,0", "Arial,204" },
2679 { "Courier New Cyr,0", "Courier New,204" },
2680 { "Times New Roman Cyr,0", "Times New Roman,204" }
2683 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2684 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2685 "Tahoma","Times New Roman", /* FIXME unverified */
2686 "Fixedsys,161", "System,161",
2687 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2688 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2689 { "Arial Greek,0", "Arial,161" },
2690 { "Courier New Greek,0", "Courier New,161" },
2691 { "Times New Roman Greek,0", "Times New Roman,161" }
2694 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2695 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2696 "Tahoma","Times New Roman", /* FIXME unverified */
2697 "Fixedsys,162", "System,162",
2698 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2699 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2700 { "Arial Tur,0", "Arial,162" },
2701 { "Courier New Tur,0", "Courier New,162" },
2702 { "Times New Roman Tur,0", "Times New Roman,162" }
2705 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2706 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2707 "Tahoma","Times New Roman", /* FIXME unverified */
2708 "Fixedsys,177", "System,177",
2709 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2710 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2714 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2715 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2716 "Tahoma","Times New Roman", /* FIXME unverified */
2717 "Fixedsys,178", "System,178",
2718 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2719 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2723 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2724 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2725 "Tahoma","Times New Roman", /* FIXME unverified */
2726 "Fixedsys,186", "System,186",
2727 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2728 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2729 { "Arial Baltic,0", "Arial,186" },
2730 { "Courier New Baltic,0", "Courier New,186" },
2731 { "Times New Roman Baltic,0", "Times New Roman,186" }
2734 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2735 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2736 "Tahoma","Times New Roman", /* FIXME unverified */
2737 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2741 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2742 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2743 "Tahoma","Times New Roman", /* FIXME unverified */
2744 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2748 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2749 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2750 "MS UI Gothic","MS Serif",
2751 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2754 /* Chinese Simplified */
2755 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2756 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2757 "SimSun", "NSimSun",
2758 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2762 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2763 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2765 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2768 /* Chinese Traditional */
2769 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2770 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2771 "PMingLiU", "MingLiU",
2772 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2777 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2779 return ( ansi_cp
== 932 /* CP932 for Japanese */
2780 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2781 || ansi_cp
== 949 /* CP949 for Korean */
2782 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2785 static inline HKEY
create_fonts_NT_registry_key(void)
2789 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2790 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2794 static inline HKEY
create_fonts_9x_registry_key(void)
2798 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2799 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2803 static inline HKEY
create_config_fonts_registry_key(void)
2807 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2808 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2812 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2814 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2815 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2816 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2817 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2820 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2823 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2825 RegDeleteValueA(hkey
, name
);
2828 static void update_font_info(void)
2830 char buf
[40], cpbuf
[40];
2833 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2836 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2839 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2840 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2841 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2842 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2843 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2845 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2846 if (is_dbcs_ansi_cp(ansi_cp
))
2847 use_default_fallback
= TRUE
;
2850 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2852 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2857 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2859 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2861 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2864 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2868 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2869 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2871 hkey
= create_config_fonts_registry_key();
2872 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2873 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2874 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2877 hkey
= create_fonts_NT_registry_key();
2878 add_font_list(hkey
, &nls_update_font_list
[i
]);
2881 hkey
= create_fonts_9x_registry_key();
2882 add_font_list(hkey
, &nls_update_font_list
[i
]);
2885 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2887 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2888 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2889 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2890 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2892 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2893 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2894 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2895 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2896 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2897 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2898 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2899 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2901 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2902 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2903 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2911 /* Delete the FontSubstitutes from other locales */
2912 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2914 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2915 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2916 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2922 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2925 static BOOL
init_freetype(void)
2927 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2930 "Wine cannot find the FreeType font library. To enable Wine to\n"
2931 "use TrueType fonts please install a version of FreeType greater than\n"
2932 "or equal to 2.0.5.\n"
2933 "http://www.freetype.org\n");
2937 #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;}
2939 LOAD_FUNCPTR(FT_Done_Face
)
2940 LOAD_FUNCPTR(FT_Get_Char_Index
)
2941 LOAD_FUNCPTR(FT_Get_First_Char
)
2942 LOAD_FUNCPTR(FT_Get_Module
)
2943 LOAD_FUNCPTR(FT_Get_Next_Char
)
2944 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2945 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2946 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2947 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
2948 LOAD_FUNCPTR(FT_Init_FreeType
)
2949 LOAD_FUNCPTR(FT_Library_Version
)
2950 LOAD_FUNCPTR(FT_Load_Glyph
)
2951 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
2952 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2953 #ifndef FT_MULFIX_INLINED
2954 LOAD_FUNCPTR(FT_MulFix
)
2956 LOAD_FUNCPTR(FT_New_Face
)
2957 LOAD_FUNCPTR(FT_New_Memory_Face
)
2958 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2959 LOAD_FUNCPTR(FT_Outline_Transform
)
2960 LOAD_FUNCPTR(FT_Outline_Translate
)
2961 LOAD_FUNCPTR(FT_Render_Glyph
)
2962 LOAD_FUNCPTR(FT_Select_Charmap
)
2963 LOAD_FUNCPTR(FT_Set_Charmap
)
2964 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2965 LOAD_FUNCPTR(FT_Vector_Transform
)
2966 LOAD_FUNCPTR(FT_Vector_Unit
)
2968 /* Don't warn if these ones are missing */
2969 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2970 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2971 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2974 if(pFT_Init_FreeType(&library
) != 0) {
2975 ERR("Can't init FreeType library\n");
2976 wine_dlclose(ft_handle
, NULL
, 0);
2980 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2982 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2983 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2984 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2985 ((FT_Version
.patch
) & 0x0000ff);
2987 font_driver
= &freetype_funcs
;
2992 "Wine cannot find certain functions that it needs inside the FreeType\n"
2993 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2994 "FreeType to at least version 2.1.4.\n"
2995 "http://www.freetype.org\n");
2996 wine_dlclose(ft_handle
, NULL
, 0);
3001 static void init_font_list(void)
3003 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3004 static const WCHAR pathW
[] = {'P','a','t','h',0};
3006 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3007 WCHAR windowsdir
[MAX_PATH
];
3010 const char *data_dir
;
3012 delete_external_font_keys();
3014 /* load the system bitmap fonts */
3015 load_system_fonts();
3017 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3018 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3019 strcatW(windowsdir
, fontsW
);
3020 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3022 ReadFontDir(unixname
, FALSE
);
3023 HeapFree(GetProcessHeap(), 0, unixname
);
3026 /* load the system truetype fonts */
3027 data_dir
= wine_get_data_dir();
3028 if (!data_dir
) data_dir
= wine_get_build_dir();
3029 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3031 strcpy(unixname
, data_dir
);
3032 strcat(unixname
, "/fonts/");
3033 ReadFontDir(unixname
, TRUE
);
3034 HeapFree(GetProcessHeap(), 0, unixname
);
3037 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3038 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3039 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3041 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3042 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3043 &hkey
) == ERROR_SUCCESS
)
3045 LPWSTR data
, valueW
;
3046 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3047 &valuelen
, &datalen
, NULL
, NULL
);
3049 valuelen
++; /* returned value doesn't include room for '\0' */
3050 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3051 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3054 dlen
= datalen
* sizeof(WCHAR
);
3056 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3057 &dlen
) == ERROR_SUCCESS
)
3059 if(data
[0] && (data
[1] == ':'))
3061 if((unixname
= wine_get_unix_file_name(data
)))
3063 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3064 HeapFree(GetProcessHeap(), 0, unixname
);
3067 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3069 WCHAR pathW
[MAX_PATH
];
3070 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3073 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3074 if((unixname
= wine_get_unix_file_name(pathW
)))
3076 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3077 HeapFree(GetProcessHeap(), 0, unixname
);
3080 load_font_from_data_dir(data
);
3082 /* reset dlen and vlen */
3087 HeapFree(GetProcessHeap(), 0, data
);
3088 HeapFree(GetProcessHeap(), 0, valueW
);
3092 load_fontconfig_fonts();
3094 /* then look in any directories that we've specified in the config file */
3095 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3096 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3102 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3104 len
+= sizeof(WCHAR
);
3105 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3106 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3108 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3109 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3110 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3111 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3115 LPSTR next
= strchr( ptr
, ':' );
3116 if (next
) *next
++ = 0;
3117 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3118 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3120 strcpy( unixname
, home
);
3121 strcat( unixname
, ptr
+ 1 );
3122 ReadFontDir( unixname
, TRUE
);
3123 HeapFree( GetProcessHeap(), 0, unixname
);
3126 ReadFontDir( ptr
, TRUE
);
3129 HeapFree( GetProcessHeap(), 0, valueA
);
3131 HeapFree( GetProcessHeap(), 0, valueW
);
3137 /* Mac default font locations. */
3138 ReadFontDir( "/Library/Fonts", TRUE
);
3139 ReadFontDir( "/Network/Library/Fonts", TRUE
);
3140 ReadFontDir( "/System/Library/Fonts", TRUE
);
3141 if ((home
= getenv( "HOME" )))
3143 unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(home
)+15 );
3144 strcpy( unixname
, home
);
3145 strcat( unixname
, "/Library/Fonts" );
3146 ReadFontDir( unixname
, TRUE
);
3147 HeapFree( GetProcessHeap(), 0, unixname
);
3152 static BOOL
move_to_front(const WCHAR
*name
)
3154 Family
*family
, *cursor2
;
3155 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3157 if(!strcmpiW(family
->FamilyName
, name
))
3159 list_remove(&family
->entry
);
3160 list_add_head(&font_list
, &family
->entry
);
3167 static BOOL
set_default(const WCHAR
**name_list
)
3171 if (move_to_front(*name_list
)) return TRUE
;
3178 static void reorder_font_list(void)
3180 set_default( default_serif_list
);
3181 set_default( default_fixed_list
);
3182 set_default( default_sans_list
);
3185 /*************************************************************
3188 * Initialize FreeType library and create a list of available faces
3190 BOOL
WineEngInit(void)
3192 HKEY hkey_font_cache
;
3196 /* update locale dependent font info in registry */
3199 if(!init_freetype()) return FALSE
;
3201 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3203 ERR("Failed to create font mutex\n");
3206 WaitForSingleObject(font_mutex
, INFINITE
);
3208 create_font_cache_key(&hkey_font_cache
, &disposition
);
3210 if(disposition
== REG_CREATED_NEW_KEY
)
3213 load_font_list_from_cache(hkey_font_cache
);
3215 RegCloseKey(hkey_font_cache
);
3217 reorder_font_list();
3224 if(disposition
== REG_CREATED_NEW_KEY
)
3225 update_reg_entries();
3227 init_system_links();
3229 ReleaseMutex(font_mutex
);
3234 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3237 TT_HoriHeader
*pHori
;
3241 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3242 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3244 if(height
== 0) height
= 16;
3246 /* Calc. height of EM square:
3248 * For +ve lfHeight we have
3249 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3250 * Re-arranging gives:
3251 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3253 * For -ve lfHeight we have
3255 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3256 * with il = winAscent + winDescent - units_per_em]
3261 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3262 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3263 pHori
->Ascender
- pHori
->Descender
);
3265 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3266 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3274 static struct font_mapping
*map_font_file( const char *name
)
3276 struct font_mapping
*mapping
;
3280 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3281 if (fstat( fd
, &st
) == -1) goto error
;
3283 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3285 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3287 mapping
->refcount
++;
3292 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3295 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3298 if (mapping
->data
== MAP_FAILED
)
3300 HeapFree( GetProcessHeap(), 0, mapping
);
3303 mapping
->refcount
= 1;
3304 mapping
->dev
= st
.st_dev
;
3305 mapping
->ino
= st
.st_ino
;
3306 mapping
->size
= st
.st_size
;
3307 list_add_tail( &mappings_list
, &mapping
->entry
);
3315 static void unmap_font_file( struct font_mapping
*mapping
)
3317 if (!--mapping
->refcount
)
3319 list_remove( &mapping
->entry
);
3320 munmap( mapping
->data
, mapping
->size
);
3321 HeapFree( GetProcessHeap(), 0, mapping
);
3325 static LONG
load_VDMX(GdiFont
*, LONG
);
3327 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3334 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3338 if (!(font
->mapping
= map_font_file( face
->file
)))
3340 WARN("failed to map %s\n", debugstr_a(face
->file
));
3343 data_ptr
= font
->mapping
->data
;
3344 data_size
= font
->mapping
->size
;
3348 data_ptr
= face
->font_data_ptr
;
3349 data_size
= face
->font_data_size
;
3352 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3354 ERR("FT_New_Face rets %d\n", err
);
3358 /* set it here, as load_VDMX needs it */
3359 font
->ft_face
= ft_face
;
3361 if(FT_IS_SCALABLE(ft_face
)) {
3362 /* load the VDMX table if we have one */
3363 font
->ppem
= load_VDMX(font
, height
);
3365 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3366 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3368 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3369 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3371 font
->ppem
= height
;
3372 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3373 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3379 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3381 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3382 a single face with the requested charset. The idea is to check if
3383 the selected font supports the current ANSI codepage, if it does
3384 return the corresponding charset, else return the first charset */
3387 int acp
= GetACP(), i
;
3391 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3393 const SYSTEM_LINKS
*font_link
;
3395 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
3396 return csi
.ciCharset
;
3398 font_link
= find_font_link(family_name
);
3399 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
3400 return csi
.ciCharset
;
3403 for(i
= 0; i
< 32; i
++) {
3405 if(face
->fs
.fsCsb
[0] & fs0
) {
3406 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3408 return csi
.ciCharset
;
3411 FIXME("TCI failing on %x\n", fs0
);
3415 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3416 face
->fs
.fsCsb
[0], face
->file
);
3418 return DEFAULT_CHARSET
;
3421 static GdiFont
*alloc_font(void)
3423 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3425 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3426 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3428 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3429 ret
->total_kern_pairs
= (DWORD
)-1;
3430 ret
->kern_pairs
= NULL
;
3431 list_init(&ret
->hfontlist
);
3432 list_init(&ret
->child_fonts
);
3436 static void free_font(GdiFont
*font
)
3438 struct list
*cursor
, *cursor2
;
3441 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3443 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3444 list_remove(cursor
);
3446 free_font(child
->font
);
3447 HeapFree(GetProcessHeap(), 0, child
);
3450 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3452 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3453 DeleteObject(hfontlist
->hfont
);
3454 list_remove(&hfontlist
->entry
);
3455 HeapFree(GetProcessHeap(), 0, hfontlist
);
3458 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3459 if (font
->mapping
) unmap_font_file( font
->mapping
);
3460 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3461 HeapFree(GetProcessHeap(), 0, font
->potm
);
3462 HeapFree(GetProcessHeap(), 0, font
->name
);
3463 for (i
= 0; i
< font
->gmsize
; i
++)
3464 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3465 HeapFree(GetProcessHeap(), 0, font
->gm
);
3466 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3467 HeapFree(GetProcessHeap(), 0, font
);
3471 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3473 FT_Face ft_face
= font
->ft_face
;
3477 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3484 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3486 /* make sure value of len is the value freetype says it needs */
3489 FT_ULong needed
= 0;
3490 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3491 if( !err
&& needed
< len
) len
= needed
;
3493 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3496 TRACE("Can't find table %c%c%c%c\n",
3497 /* bytes were reversed */
3498 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3499 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3505 /*************************************************************
3508 * load the vdmx entry for the specified height
3511 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3512 ( ( (FT_ULong)_x4 << 24 ) | \
3513 ( (FT_ULong)_x3 << 16 ) | \
3514 ( (FT_ULong)_x2 << 8 ) | \
3517 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3532 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3536 BYTE devXRatio
, devYRatio
;
3537 USHORT numRecs
, numRatios
;
3538 DWORD result
, offset
= -1;
3542 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3544 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3547 /* FIXME: need the real device aspect ratio */
3551 numRecs
= GET_BE_WORD(hdr
[1]);
3552 numRatios
= GET_BE_WORD(hdr
[2]);
3554 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3555 for(i
= 0; i
< numRatios
; i
++) {
3558 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3559 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3562 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3564 if((ratio
.xRatio
== 0 &&
3565 ratio
.yStartRatio
== 0 &&
3566 ratio
.yEndRatio
== 0) ||
3567 (devXRatio
== ratio
.xRatio
&&
3568 devYRatio
>= ratio
.yStartRatio
&&
3569 devYRatio
<= ratio
.yEndRatio
))
3571 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3572 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3573 offset
= GET_BE_WORD(tmp
);
3579 FIXME("No suitable ratio found\n");
3583 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3585 BYTE startsz
, endsz
;
3588 recs
= GET_BE_WORD(group
.recs
);
3589 startsz
= group
.startsz
;
3590 endsz
= group
.endsz
;
3592 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3594 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3595 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3596 if(result
== GDI_ERROR
) {
3597 FIXME("Failed to retrieve vTable\n");
3602 for(i
= 0; i
< recs
; i
++) {
3603 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3604 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3605 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3607 if(yMax
+ -yMin
== height
) {
3610 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3613 if(yMax
+ -yMin
> height
) {
3616 goto end
; /* failed */
3618 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3619 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3620 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3621 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3627 TRACE("ppem not found for height %d\n", height
);
3631 HeapFree(GetProcessHeap(), 0, vTable
);
3637 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3639 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3640 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3641 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3642 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3643 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3646 static void calc_hash(FONT_DESC
*pfd
)
3648 DWORD hash
= 0, *ptr
, two_chars
;
3652 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3654 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3656 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3658 pwc
= (WCHAR
*)&two_chars
;
3660 *pwc
= toupperW(*pwc
);
3662 *pwc
= toupperW(*pwc
);
3666 hash
^= !pfd
->can_use_bitmap
;
3671 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3676 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3680 fd
.can_use_bitmap
= can_use_bitmap
;
3683 /* try the child list */
3684 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3685 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3686 if(!fontcmp(ret
, &fd
)) {
3687 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3688 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3689 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3690 if(hflist
->hfont
== hfont
)
3696 /* try the in-use list */
3697 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3698 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3699 if(!fontcmp(ret
, &fd
)) {
3700 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3701 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3702 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3703 if(hflist
->hfont
== hfont
)
3706 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3707 hflist
->hfont
= hfont
;
3708 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3713 /* then the unused list */
3714 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3715 while(font_elem_ptr
) {
3716 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3717 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3718 if(!fontcmp(ret
, &fd
)) {
3719 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3720 assert(list_empty(&ret
->hfontlist
));
3721 TRACE("Found %p in unused list\n", ret
);
3722 list_remove(&ret
->entry
);
3723 list_add_head(&gdi_font_list
, &ret
->entry
);
3724 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3725 hflist
->hfont
= hfont
;
3726 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3733 static void add_to_cache(GdiFont
*font
)
3735 static DWORD cache_num
= 1;
3737 font
->cache_num
= cache_num
++;
3738 list_add_head(&gdi_font_list
, &font
->entry
);
3741 /*************************************************************
3742 * create_child_font_list
3744 static BOOL
create_child_font_list(GdiFont
*font
)
3747 SYSTEM_LINKS
*font_link
;
3748 CHILD_FONT
*font_link_entry
, *new_child
;
3752 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3753 font_name
= psub
? psub
->to
.name
: font
->name
;
3754 font_link
= find_font_link(font_name
);
3755 if (font_link
!= NULL
)
3757 TRACE("found entry in system list\n");
3758 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3760 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3761 new_child
->face
= font_link_entry
->face
;
3762 new_child
->font
= NULL
;
3763 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3764 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3769 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3770 * Sans Serif. This is how asian windows get default fallbacks for fonts
3772 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3773 font
->charset
!= OEM_CHARSET
&&
3774 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3776 font_link
= find_font_link(szDefaultFallbackLink
);
3777 if (font_link
!= NULL
)
3779 TRACE("found entry in default fallback list\n");
3780 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3782 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3783 new_child
->face
= font_link_entry
->face
;
3784 new_child
->font
= NULL
;
3785 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3786 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3795 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3797 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3799 if (pFT_Set_Charmap
)
3802 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3804 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3806 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3808 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3810 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3811 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3813 switch (ft_face
->charmaps
[i
]->platform_id
)
3816 cmap_def
= ft_face
->charmaps
[i
];
3818 case 0: /* Apple Unicode */
3819 cmap0
= ft_face
->charmaps
[i
];
3821 case 1: /* Macintosh */
3822 cmap1
= ft_face
->charmaps
[i
];
3825 cmap2
= ft_face
->charmaps
[i
];
3827 case 3: /* Microsoft */
3828 cmap3
= ft_face
->charmaps
[i
];
3833 if (cmap3
) /* prefer Microsoft cmap table */
3834 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3836 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3838 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3840 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3842 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3844 return ft_err
== FT_Err_Ok
;
3847 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3851 /*************************************************************
3854 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
3855 LPCWSTR output
, const DEVMODEW
*devmode
)
3857 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
3859 if (!physdev
) return FALSE
;
3860 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
3865 /*************************************************************
3868 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
3870 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3871 HeapFree( GetProcessHeap(), 0, physdev
);
3876 /*************************************************************
3877 * freetype_SelectFont
3879 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
3881 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3883 Face
*face
, *best
, *best_bitmap
;
3884 Family
*family
, *last_resort_family
;
3885 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
3886 INT height
, width
= 0;
3887 unsigned int score
= 0, new_score
;
3888 signed int diff
= 0, newdiff
;
3889 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
3894 FontSubst
*psub
= NULL
;
3895 DC
*dc
= get_dc_ptr( dev
->hdc
);
3896 const SYSTEM_LINKS
*font_link
;
3898 if (!hfont
) /* notification that the font has been changed by another driver */
3901 physdev
->font
= NULL
;
3902 release_dc_ptr( dc
);
3906 GetObjectW( hfont
, sizeof(lf
), &lf
);
3907 lf
.lfWidth
= abs(lf
.lfWidth
);
3909 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
3911 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3912 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3913 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3916 if(dc
->GraphicsMode
== GM_ADVANCED
)
3918 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3919 /* Try to avoid not necessary glyph transformations */
3920 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3922 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3923 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3924 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3929 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3930 font scaling abilities. */
3931 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3932 dcmat
.eM21
= dcmat
.eM12
= 0;
3933 if (dc
->vport2WorldValid
)
3935 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
3936 lf
.lfOrientation
= -lf
.lfOrientation
;
3937 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
3938 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
3942 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3943 dcmat
.eM21
, dcmat
.eM22
);
3946 EnterCriticalSection( &freetype_cs
);
3948 /* check the cache first */
3949 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3950 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3954 if(list_empty(&font_list
)) /* No fonts installed */
3956 TRACE("No fonts installed\n");
3960 TRACE("not in cache\n");
3963 ret
->font_desc
.matrix
= dcmat
;
3964 ret
->font_desc
.lf
= lf
;
3965 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3966 calc_hash(&ret
->font_desc
);
3967 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3968 hflist
->hfont
= hfont
;
3969 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3971 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3972 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3973 original value lfCharSet. Note this is a special case for
3974 Symbol and doesn't happen at least for "Wingdings*" */
3976 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3977 lf
.lfCharSet
= SYMBOL_CHARSET
;
3979 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3980 switch(lf
.lfCharSet
) {
3981 case DEFAULT_CHARSET
:
3982 csi
.fs
.fsCsb
[0] = 0;
3985 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
3986 csi
.fs
.fsCsb
[0] = 0;
3992 if(lf
.lfFaceName
[0] != '\0') {
3993 CHILD_FONT
*font_link_entry
;
3994 LPWSTR FaceName
= lf
.lfFaceName
;
3996 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
3999 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4000 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4001 if (psub
->to
.charset
!= -1)
4002 lf
.lfCharSet
= psub
->to
.charset
;
4005 /* We want a match on name and charset or just name if
4006 charset was DEFAULT_CHARSET. If the latter then
4007 we fixup the returned charset later in get_nearest_charset
4008 where we'll either use the charset of the current ansi codepage
4009 or if that's unavailable the first charset that the font supports.
4011 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4012 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4013 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4014 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4016 font_link
= find_font_link(family
->FamilyName
);
4017 face_list
= get_face_list_from_family(family
);
4018 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4019 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4020 if (!(face
->scalable
|| can_use_bitmap
))
4022 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4024 if (font_link
!= NULL
&&
4025 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4027 if (!csi
.fs
.fsCsb
[0])
4033 /* Search by full face name. */
4034 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4035 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4036 face_list
= get_face_list_from_family(family
);
4037 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4038 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4039 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4040 (face
->scalable
|| can_use_bitmap
))
4042 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4044 font_link
= find_font_link(family
->FamilyName
);
4045 if (font_link
!= NULL
&&
4046 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4053 * Try check the SystemLink list first for a replacement font.
4054 * We may find good replacements there.
4056 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4058 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4059 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4061 TRACE("found entry in system list\n");
4062 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4064 const SYSTEM_LINKS
*links
;
4066 face
= font_link_entry
->face
;
4067 if (!(face
->scalable
|| can_use_bitmap
))
4069 family
= face
->family
;
4070 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4072 links
= find_font_link(family
->FamilyName
);
4073 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4080 psub
= NULL
; /* substitution is no more relevant */
4082 /* If requested charset was DEFAULT_CHARSET then try using charset
4083 corresponding to the current ansi codepage */
4084 if (!csi
.fs
.fsCsb
[0])
4087 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4088 FIXME("TCI failed on codepage %d\n", acp
);
4089 csi
.fs
.fsCsb
[0] = 0;
4091 lf
.lfCharSet
= csi
.ciCharset
;
4094 want_vertical
= (lf
.lfFaceName
[0] == '@');
4096 /* Face families are in the top 4 bits of lfPitchAndFamily,
4097 so mask with 0xF0 before testing */
4099 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4100 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4101 strcpyW(lf
.lfFaceName
, defFixed
);
4102 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4103 strcpyW(lf
.lfFaceName
, defSerif
);
4104 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4105 strcpyW(lf
.lfFaceName
, defSans
);
4107 strcpyW(lf
.lfFaceName
, defSans
);
4108 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4109 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4110 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4111 font_link
= find_font_link(family
->FamilyName
);
4112 face_list
= get_face_list_from_family(family
);
4113 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4114 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4115 if (!(face
->scalable
|| can_use_bitmap
))
4117 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4119 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4125 last_resort_family
= NULL
;
4126 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4127 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4128 font_link
= find_font_link(family
->FamilyName
);
4129 face_list
= get_face_list_from_family(family
);
4130 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4131 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4132 if(face
->vertical
== want_vertical
&&
4133 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4134 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4137 if(can_use_bitmap
&& !last_resort_family
)
4138 last_resort_family
= family
;
4143 if(last_resort_family
) {
4144 family
= last_resort_family
;
4145 csi
.fs
.fsCsb
[0] = 0;
4149 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4150 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4151 face_list
= get_face_list_from_family(family
);
4152 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4153 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4154 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4155 csi
.fs
.fsCsb
[0] = 0;
4156 WARN("just using first face for now\n");
4159 if(can_use_bitmap
&& !last_resort_family
)
4160 last_resort_family
= family
;
4163 if(!last_resort_family
) {
4164 FIXME("can't find a single appropriate font - bailing\n");
4170 WARN("could only find a bitmap font - this will probably look awful!\n");
4171 family
= last_resort_family
;
4172 csi
.fs
.fsCsb
[0] = 0;
4175 it
= lf
.lfItalic
? 1 : 0;
4176 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4178 height
= lf
.lfHeight
;
4180 face
= best
= best_bitmap
= NULL
;
4181 font_link
= find_font_link(family
->FamilyName
);
4182 face_list
= get_face_list_from_family(family
);
4183 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4185 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4186 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4191 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4192 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4193 new_score
= (italic
^ it
) + (bold
^ bd
);
4194 if(!best
|| new_score
<= score
)
4196 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4197 italic
, bold
, it
, bd
);
4200 if(best
->scalable
&& score
== 0) break;
4204 newdiff
= height
- (signed int)(best
->size
.height
);
4206 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4207 if(!best_bitmap
|| new_score
< score
||
4208 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4210 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4213 if(score
== 0 && diff
== 0) break;
4220 face
= best
->scalable
? best
: best_bitmap
;
4221 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4222 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4225 height
= lf
.lfHeight
;
4229 if(csi
.fs
.fsCsb
[0]) {
4230 ret
->charset
= lf
.lfCharSet
;
4231 ret
->codepage
= csi
.ciACP
;
4234 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4236 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4237 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4239 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4241 if(!face
->scalable
) {
4242 /* Windows uses integer scaling factors for bitmap fonts */
4243 INT scale
, scaled_height
;
4244 GdiFont
*cachedfont
;
4246 /* FIXME: rotation of bitmap fonts is ignored */
4247 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4249 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4250 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4251 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4252 /* As we changed the matrix, we need to search the cache for the font again,
4253 * otherwise we might explode the cache. */
4254 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4255 TRACE("Found cached font after non-scalable matrix rescale!\n");
4260 calc_hash(&ret
->font_desc
);
4262 if (height
!= 0) height
= diff
;
4263 height
+= face
->size
.height
;
4265 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4266 scaled_height
= scale
* face
->size
.height
;
4267 /* Only jump to the next height if the difference <= 25% original height */
4268 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4269 /* The jump between unscaled and doubled is delayed by 1 */
4270 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4271 ret
->scale_y
= scale
;
4273 width
= face
->size
.x_ppem
>> 6;
4274 height
= face
->size
.y_ppem
>> 6;
4278 TRACE("font scale y: %f\n", ret
->scale_y
);
4280 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4289 ret
->ntmFlags
= face
->ntmFlags
;
4291 if (ret
->charset
== SYMBOL_CHARSET
&&
4292 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4295 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4299 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4302 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4303 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4304 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4305 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4306 create_child_font_list(ret
);
4308 if (face
->vertical
) /* We need to try to load the GSUB table */
4310 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4311 if (length
!= GDI_ERROR
)
4313 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4314 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4315 TRACE("Loaded GSUB table of %i bytes\n",length
);
4319 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4326 physdev
->font
= ret
;
4328 LeaveCriticalSection( &freetype_cs
);
4329 release_dc_ptr( dc
);
4330 return ret
? hfont
: 0;
4333 static void dump_gdi_font_list(void)
4336 struct list
*elem_ptr
;
4338 TRACE("---------- gdiFont Cache ----------\n");
4339 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4340 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4341 TRACE("gdiFont=%p %s %d\n",
4342 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4345 TRACE("---------- Unused gdiFont Cache ----------\n");
4346 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4347 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4348 TRACE("gdiFont=%p %s %d\n",
4349 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4352 TRACE("---------- Child gdiFont Cache ----------\n");
4353 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4354 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4355 TRACE("gdiFont=%p %s %d\n",
4356 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4360 /*************************************************************
4361 * WineEngDestroyFontInstance
4363 * free the gdiFont associated with this handle
4366 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4371 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4375 EnterCriticalSection( &freetype_cs
);
4377 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4379 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4380 while(hfontlist_elem_ptr
) {
4381 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4382 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4383 if(hflist
->hfont
== handle
) {
4384 TRACE("removing child font %p from child list\n", gdiFont
);
4385 list_remove(&gdiFont
->entry
);
4386 LeaveCriticalSection( &freetype_cs
);
4392 TRACE("destroying hfont=%p\n", handle
);
4394 dump_gdi_font_list();
4396 font_elem_ptr
= list_head(&gdi_font_list
);
4397 while(font_elem_ptr
) {
4398 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4399 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4401 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4402 while(hfontlist_elem_ptr
) {
4403 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4404 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4405 if(hflist
->hfont
== handle
) {
4406 list_remove(&hflist
->entry
);
4407 HeapFree(GetProcessHeap(), 0, hflist
);
4411 if(list_empty(&gdiFont
->hfontlist
)) {
4412 TRACE("Moving to Unused list\n");
4413 list_remove(&gdiFont
->entry
);
4414 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4419 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4420 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4421 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4422 while(font_elem_ptr
) {
4423 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4424 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4425 TRACE("freeing %p\n", gdiFont
);
4426 list_remove(&gdiFont
->entry
);
4429 LeaveCriticalSection( &freetype_cs
);
4433 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4440 id
+= IDS_FIRST_SCRIPT
;
4441 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4442 if (!rsrc
) return 0;
4443 hMem
= LoadResource( gdi32_module
, rsrc
);
4444 if (!hMem
) return 0;
4446 p
= LockResource( hMem
);
4448 while (id
--) p
+= *p
+ 1;
4450 i
= min(LF_FACESIZE
- 1, *p
);
4451 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4457 /***************************************************
4458 * create_enum_charset_list
4460 * This function creates charset enumeration list because in DEFAULT_CHARSET
4461 * case, the ANSI codepage's charset takes precedence over other charsets.
4462 * This function works as a filter other than DEFAULT_CHARSET case.
4464 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4469 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4470 csi
.fs
.fsCsb
[0] != 0) {
4471 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4472 list
->element
[n
].charset
= csi
.ciCharset
;
4473 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4476 else { /* charset is DEFAULT_CHARSET or invalid. */
4479 /* Set the current codepage's charset as the first element. */
4481 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4482 csi
.fs
.fsCsb
[0] != 0) {
4483 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4484 list
->element
[n
].charset
= csi
.ciCharset
;
4485 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4489 /* Fill out left elements. */
4490 for (i
= 0; i
< 32; i
++) {
4492 fs
.fsCsb
[0] = 1L << i
;
4494 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4495 continue; /* skip, already added. */
4496 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4497 continue; /* skip, this is an invalid fsCsb bit. */
4499 list
->element
[n
].mask
= fs
.fsCsb
[0];
4500 list
->element
[n
].charset
= csi
.ciCharset
;
4501 load_script_name( i
, list
->element
[n
].name
);
4510 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4511 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4516 if (face
->cached_enum_data
)
4519 *pelf
= face
->cached_enum_data
->elf
;
4520 *pntm
= face
->cached_enum_data
->ntm
;
4521 *ptype
= face
->cached_enum_data
->type
;
4525 font
= alloc_font();
4527 if(face
->scalable
) {
4528 height
= -2048; /* 2048 is the most common em size */
4531 height
= face
->size
.y_ppem
>> 6;
4532 width
= face
->size
.x_ppem
>> 6;
4534 font
->scale_y
= 1.0;
4536 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4542 font
->name
= strdupW(face
->family
->FamilyName
);
4543 font
->ntmFlags
= face
->ntmFlags
;
4545 if (get_outline_text_metrics(font
))
4547 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4549 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4551 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4552 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4554 lstrcpynW(pelf
->elfFullName
,
4555 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4557 lstrcpynW(pelf
->elfStyle
,
4558 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4563 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4565 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4567 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4569 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4571 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4572 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4575 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4576 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4577 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4578 pntm
->ntmFontSig
= face
->fs
;
4580 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4582 pelf
->elfLogFont
.lfEscapement
= 0;
4583 pelf
->elfLogFont
.lfOrientation
= 0;
4584 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4585 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4586 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4587 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4588 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4589 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4590 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4591 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4592 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4593 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4594 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4597 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4598 *ptype
|= TRUETYPE_FONTTYPE
;
4599 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4600 *ptype
|= DEVICE_FONTTYPE
;
4601 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4602 *ptype
|= RASTER_FONTTYPE
;
4604 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4605 if (face
->cached_enum_data
)
4607 face
->cached_enum_data
->elf
= *pelf
;
4608 face
->cached_enum_data
->ntm
= *pntm
;
4609 face
->cached_enum_data
->type
= *ptype
;
4615 static void create_full_name(WCHAR
*full_name
, const WCHAR
*family_name
, const WCHAR
*style_name
)
4617 static const WCHAR spaceW
[] = { ' ', 0 };
4619 strcpyW(full_name
, family_name
);
4620 strcatW(full_name
, spaceW
);
4621 strcatW(full_name
, style_name
);
4624 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4626 const struct list
*face_list
, *face_elem_ptr
;
4628 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4630 face_list
= get_face_list_from_family(family
);
4631 LIST_FOR_EACH(face_elem_ptr
, face_list
)
4633 WCHAR full_family_name
[LF_FULLFACESIZE
];
4634 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4636 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4638 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4639 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4643 create_full_name(full_family_name
, family
->FamilyName
, face
->StyleName
);
4644 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4650 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
4652 WCHAR full_family_name
[LF_FULLFACESIZE
];
4654 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
4656 if (strlenW(family_name
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4658 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4659 debugstr_w(family_name
), debugstr_w(face
->StyleName
));
4663 create_full_name(full_family_name
, family_name
, face
->StyleName
);
4664 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4667 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
4668 FONTENUMPROCW proc
, LPARAM lparam
)
4671 NEWTEXTMETRICEXW ntm
;
4675 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4676 for(i
= 0; i
< list
->total
; i
++) {
4677 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4678 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4679 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4680 i
= list
->total
; /* break out of loop after enumeration */
4681 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4684 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4685 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4686 if (!elf
.elfScript
[0])
4687 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4689 /* Font Replacement */
4690 if (family
!= face
->family
)
4692 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
4693 create_full_name(elf
.elfFullName
, family
->FamilyName
, face
->StyleName
);
4695 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4696 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4697 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4698 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4699 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4700 ntm
.ntmTm
.ntmFlags
);
4701 /* release section before callback (FIXME) */
4702 LeaveCriticalSection( &freetype_cs
);
4703 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4704 EnterCriticalSection( &freetype_cs
);
4709 /*************************************************************
4710 * freetype_EnumFonts
4712 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4716 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4718 struct enum_charset_list enum_charsets
;
4722 lf
.lfCharSet
= DEFAULT_CHARSET
;
4723 lf
.lfPitchAndFamily
= 0;
4724 lf
.lfFaceName
[0] = 0;
4728 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4730 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4733 EnterCriticalSection( &freetype_cs
);
4734 if(plf
->lfFaceName
[0]) {
4736 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4739 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4740 debugstr_w(psub
->to
.name
));
4742 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4746 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4747 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4748 if(family_matches(family
, plf
)) {
4749 face_list
= get_face_list_from_family(family
);
4750 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4751 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4752 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
4753 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4758 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4759 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4760 face_list
= get_face_list_from_family(family
);
4761 face_elem_ptr
= list_head(face_list
);
4762 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4763 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4766 LeaveCriticalSection( &freetype_cs
);
4770 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4772 pt
->x
.value
= vec
->x
>> 6;
4773 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4774 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4775 pt
->y
.value
= vec
->y
>> 6;
4776 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4777 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4781 /***************************************************
4782 * According to the MSDN documentation on WideCharToMultiByte,
4783 * certain codepages cannot set the default_used parameter.
4784 * This returns TRUE if the codepage can set that parameter, false else
4785 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4787 static BOOL
codepage_sets_default_used(UINT codepage
)
4801 * GSUB Table handling functions
4804 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4806 const GSUB_CoverageFormat1
* cf1
;
4810 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4812 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4814 TRACE("Coverage Format 1, %i glyphs\n",count
);
4815 for (i
= 0; i
< count
; i
++)
4816 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4820 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4822 const GSUB_CoverageFormat2
* cf2
;
4825 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4827 count
= GET_BE_WORD(cf2
->RangeCount
);
4828 TRACE("Coverage Format 2, %i ranges\n",count
);
4829 for (i
= 0; i
< count
; i
++)
4831 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4833 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4834 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4836 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4837 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4843 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4848 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4850 const GSUB_ScriptList
*script
;
4851 const GSUB_Script
*deflt
= NULL
;
4853 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4855 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4856 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4858 const GSUB_Script
*scr
;
4861 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4862 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4864 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4866 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4872 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4876 const GSUB_LangSys
*Lang
;
4878 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4880 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4882 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4883 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4885 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4888 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4891 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4897 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4900 const GSUB_FeatureList
*feature
;
4901 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4903 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4904 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4906 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4907 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4909 const GSUB_Feature
*feat
;
4910 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4917 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4921 const GSUB_LookupList
*lookup
;
4922 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4924 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4925 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4927 const GSUB_LookupTable
*look
;
4928 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4929 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4930 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4931 if (GET_BE_WORD(look
->LookupType
) != 1)
4932 FIXME("We only handle SubType 1\n");
4937 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4939 const GSUB_SingleSubstFormat1
*ssf1
;
4940 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4941 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4942 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4944 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4945 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4946 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4948 TRACE(" Glyph 0x%x ->",glyph
);
4949 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4950 TRACE(" 0x%x\n",glyph
);
4955 const GSUB_SingleSubstFormat2
*ssf2
;
4959 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4960 offset
= GET_BE_WORD(ssf1
->Coverage
);
4961 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4962 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4963 TRACE(" Coverage index %i\n",index
);
4966 TRACE(" Glyph is 0x%x ->",glyph
);
4967 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4968 TRACE("0x%x\n",glyph
);
4977 static const char* get_opentype_script(const GdiFont
*font
)
4980 * I am not sure if this is the correct way to generate our script tag
4983 switch (font
->charset
)
4985 case ANSI_CHARSET
: return "latn";
4986 case BALTIC_CHARSET
: return "latn"; /* ?? */
4987 case CHINESEBIG5_CHARSET
: return "hani";
4988 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4989 case GB2312_CHARSET
: return "hani";
4990 case GREEK_CHARSET
: return "grek";
4991 case HANGUL_CHARSET
: return "hang";
4992 case RUSSIAN_CHARSET
: return "cyrl";
4993 case SHIFTJIS_CHARSET
: return "kana";
4994 case TURKISH_CHARSET
: return "latn"; /* ?? */
4995 case VIETNAMESE_CHARSET
: return "latn";
4996 case JOHAB_CHARSET
: return "latn"; /* ?? */
4997 case ARABIC_CHARSET
: return "arab";
4998 case HEBREW_CHARSET
: return "hebr";
4999 case THAI_CHARSET
: return "thai";
5000 default: return "latn";
5004 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5006 const GSUB_Header
*header
;
5007 const GSUB_Script
*script
;
5008 const GSUB_LangSys
*language
;
5009 const GSUB_Feature
*feature
;
5011 if (!font
->GSUB_Table
)
5014 header
= font
->GSUB_Table
;
5016 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5019 TRACE("Script not found\n");
5022 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5025 TRACE("Language not found\n");
5028 feature
= GSUB_get_feature(header
, language
, "vrt2");
5030 feature
= GSUB_get_feature(header
, language
, "vert");
5033 TRACE("vrt2/vert feature not found\n");
5036 return GSUB_apply_feature(header
, feature
, glyph
);
5039 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5043 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5044 WCHAR wc
= (WCHAR
)glyph
;
5046 BOOL
*default_used_pointer
;
5049 default_used_pointer
= NULL
;
5050 default_used
= FALSE
;
5051 if (codepage_sets_default_used(font
->codepage
))
5052 default_used_pointer
= &default_used
;
5053 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5056 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5057 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5061 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5063 if (glyph
< 0x100) glyph
+= 0xf000;
5064 /* there is a number of old pre-Unicode "broken" TTFs, which
5065 do have symbols at U+00XX instead of U+f0XX */
5066 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5067 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5069 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5074 /*************************************************************
5075 * freetype_GetGlyphIndices
5077 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5079 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5082 BOOL got_default
= FALSE
;
5086 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5087 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5090 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5092 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5097 EnterCriticalSection( &freetype_cs
);
5099 for(i
= 0; i
< count
; i
++)
5101 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5106 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5108 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5109 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5114 get_text_metrics(physdev
->font
, &textm
);
5115 default_char
= textm
.tmDefaultChar
;
5119 pgi
[i
] = default_char
;
5122 LeaveCriticalSection( &freetype_cs
);
5126 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5128 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5129 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5132 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5134 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5135 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5138 static inline BYTE
get_max_level( UINT format
)
5142 case GGO_GRAY2_BITMAP
: return 4;
5143 case GGO_GRAY4_BITMAP
: return 16;
5144 case GGO_GRAY8_BITMAP
: return 64;
5149 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5151 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5152 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5155 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5156 FT_Face ft_face
= incoming_font
->ft_face
;
5157 GdiFont
*font
= incoming_font
;
5158 FT_UInt glyph_index
;
5159 DWORD width
, height
, pitch
, needed
= 0;
5160 FT_Bitmap ft_bitmap
;
5162 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5164 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5165 double widthRatio
= 1.0;
5166 FT_Matrix transMat
= identityMat
;
5167 FT_Matrix transMatUnrotated
;
5168 BOOL needsTransform
= FALSE
;
5169 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5170 UINT original_index
;
5172 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5173 buflen
, buf
, lpmat
);
5175 TRACE("font transform %f %f %f %f\n",
5176 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5177 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5179 if(format
& GGO_GLYPH_INDEX
) {
5180 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5181 original_index
= glyph
;
5182 format
&= ~GGO_GLYPH_INDEX
;
5184 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5185 ft_face
= font
->ft_face
;
5186 original_index
= glyph_index
;
5189 if(format
& GGO_UNHINTED
) {
5190 load_flags
|= FT_LOAD_NO_HINTING
;
5191 format
&= ~GGO_UNHINTED
;
5194 /* tategaki never appears to happen to lower glyph index */
5195 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5198 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5199 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5200 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5201 font
->gmsize
* sizeof(GM
*));
5203 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5204 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5206 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5207 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5208 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5209 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5210 return 1; /* FIXME */
5214 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5215 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5217 /* Scaling factor */
5222 get_text_metrics(font
, &tm
);
5224 widthRatio
= (double)font
->aveWidth
;
5225 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5228 widthRatio
= font
->scale_y
;
5230 /* Scaling transform */
5231 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5234 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5237 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5239 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5240 needsTransform
= TRUE
;
5243 /* Slant transform */
5244 if (font
->fake_italic
) {
5247 slantMat
.xx
= (1 << 16);
5248 slantMat
.xy
= ((1 << 16) >> 2);
5250 slantMat
.yy
= (1 << 16);
5251 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5252 needsTransform
= TRUE
;
5255 /* Rotation transform */
5256 transMatUnrotated
= transMat
;
5257 if(font
->orientation
&& !tategaki
) {
5258 FT_Matrix rotationMat
;
5260 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5261 pFT_Vector_Unit(&vecAngle
, angle
);
5262 rotationMat
.xx
= vecAngle
.x
;
5263 rotationMat
.xy
= -vecAngle
.y
;
5264 rotationMat
.yx
= -rotationMat
.xy
;
5265 rotationMat
.yy
= rotationMat
.xx
;
5267 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5268 needsTransform
= TRUE
;
5271 /* World transform */
5272 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5275 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5276 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5277 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5278 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5279 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5280 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5281 needsTransform
= TRUE
;
5284 /* Extra transformation specified by caller */
5285 if (!is_identity_MAT2(lpmat
))
5288 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5289 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5290 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5291 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5292 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5293 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5294 needsTransform
= TRUE
;
5297 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5298 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5299 format
== GGO_GRAY8_BITMAP
))
5301 load_flags
|= FT_LOAD_NO_BITMAP
;
5304 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5307 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5311 if(!needsTransform
) {
5312 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5313 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5314 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5316 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5317 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5318 ft_face
->glyph
->metrics
.height
) & -64;
5319 lpgm
->gmCellIncX
= adv
;
5320 lpgm
->gmCellIncY
= 0;
5327 for(xc
= 0; xc
< 2; xc
++) {
5328 for(yc
= 0; yc
< 2; yc
++) {
5329 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5330 xc
* ft_face
->glyph
->metrics
.width
);
5331 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5332 yc
* ft_face
->glyph
->metrics
.height
;
5333 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5334 pFT_Vector_Transform(&vec
, &transMat
);
5335 if(xc
== 0 && yc
== 0) {
5336 left
= right
= vec
.x
;
5337 top
= bottom
= vec
.y
;
5339 if(vec
.x
< left
) left
= vec
.x
;
5340 else if(vec
.x
> right
) right
= vec
.x
;
5341 if(vec
.y
< bottom
) bottom
= vec
.y
;
5342 else if(vec
.y
> top
) top
= vec
.y
;
5347 right
= (right
+ 63) & -64;
5348 bottom
= bottom
& -64;
5349 top
= (top
+ 63) & -64;
5351 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5352 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5354 pFT_Vector_Transform(&vec
, &transMat
);
5355 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5356 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5358 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5360 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5361 adv
= (vec
.x
+63) >> 6;
5365 bbx
= (right
- left
) >> 6;
5366 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5367 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5368 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5369 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5371 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5372 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5373 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5375 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5376 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5378 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5379 FONT_GM(font
,original_index
)->adv
= adv
;
5380 FONT_GM(font
,original_index
)->lsb
= lsb
;
5381 FONT_GM(font
,original_index
)->bbx
= bbx
;
5382 FONT_GM(font
,original_index
)->init
= TRUE
;
5385 if(format
== GGO_METRICS
)
5387 return 1; /* FIXME */
5390 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5391 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5393 TRACE("loaded a bitmap\n");
5399 width
= lpgm
->gmBlackBoxX
;
5400 height
= lpgm
->gmBlackBoxY
;
5401 pitch
= ((width
+ 31) >> 5) << 2;
5402 needed
= pitch
* height
;
5404 if(!buf
|| !buflen
) break;
5406 switch(ft_face
->glyph
->format
) {
5407 case ft_glyph_format_bitmap
:
5409 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5410 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5411 INT h
= ft_face
->glyph
->bitmap
.rows
;
5413 memcpy(dst
, src
, w
);
5414 src
+= ft_face
->glyph
->bitmap
.pitch
;
5420 case ft_glyph_format_outline
:
5421 ft_bitmap
.width
= width
;
5422 ft_bitmap
.rows
= height
;
5423 ft_bitmap
.pitch
= pitch
;
5424 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5425 ft_bitmap
.buffer
= buf
;
5428 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5430 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5432 /* Note: FreeType will only set 'black' bits for us. */
5433 memset(buf
, 0, needed
);
5434 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5438 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5443 case GGO_GRAY2_BITMAP
:
5444 case GGO_GRAY4_BITMAP
:
5445 case GGO_GRAY8_BITMAP
:
5446 case WINE_GGO_GRAY16_BITMAP
:
5448 unsigned int max_level
, row
, col
;
5451 width
= lpgm
->gmBlackBoxX
;
5452 height
= lpgm
->gmBlackBoxY
;
5453 pitch
= (width
+ 3) / 4 * 4;
5454 needed
= pitch
* height
;
5456 if(!buf
|| !buflen
) break;
5458 max_level
= get_max_level( format
);
5460 switch(ft_face
->glyph
->format
) {
5461 case ft_glyph_format_bitmap
:
5463 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5464 INT h
= ft_face
->glyph
->bitmap
.rows
;
5466 memset( buf
, 0, needed
);
5468 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5469 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5470 src
+= ft_face
->glyph
->bitmap
.pitch
;
5475 case ft_glyph_format_outline
:
5477 ft_bitmap
.width
= width
;
5478 ft_bitmap
.rows
= height
;
5479 ft_bitmap
.pitch
= pitch
;
5480 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5481 ft_bitmap
.buffer
= buf
;
5484 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5486 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5488 memset(ft_bitmap
.buffer
, 0, buflen
);
5490 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5492 if (max_level
!= 255)
5494 for (row
= 0, start
= buf
; row
< height
; row
++)
5496 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5497 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5505 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5511 case WINE_GGO_HRGB_BITMAP
:
5512 case WINE_GGO_HBGR_BITMAP
:
5513 case WINE_GGO_VRGB_BITMAP
:
5514 case WINE_GGO_VBGR_BITMAP
:
5515 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5517 switch (ft_face
->glyph
->format
)
5519 case FT_GLYPH_FORMAT_BITMAP
:
5524 width
= lpgm
->gmBlackBoxX
;
5525 height
= lpgm
->gmBlackBoxY
;
5527 needed
= pitch
* height
;
5529 if (!buf
|| !buflen
) break;
5531 memset(buf
, 0, buflen
);
5533 src
= ft_face
->glyph
->bitmap
.buffer
;
5534 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5536 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5539 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5541 if ( src
[x
/ 8] & masks
[x
% 8] )
5542 ((unsigned int *)dst
)[x
] = ~0u;
5551 case FT_GLYPH_FORMAT_OUTLINE
:
5555 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5556 INT x_shift
, y_shift
;
5558 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5559 FT_Render_Mode render_mode
=
5560 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5561 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5563 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5565 if ( render_mode
== FT_RENDER_MODE_LCD
)
5567 lpgm
->gmBlackBoxX
+= 2;
5568 lpgm
->gmptGlyphOrigin
.x
-= 1;
5572 lpgm
->gmBlackBoxY
+= 2;
5573 lpgm
->gmptGlyphOrigin
.y
+= 1;
5577 width
= lpgm
->gmBlackBoxX
;
5578 height
= lpgm
->gmBlackBoxY
;
5580 needed
= pitch
* height
;
5582 if (!buf
|| !buflen
) break;
5584 memset(buf
, 0, buflen
);
5586 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5588 if ( needsTransform
)
5589 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5591 if ( pFT_Library_SetLcdFilter
)
5592 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5593 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5595 src
= ft_face
->glyph
->bitmap
.buffer
;
5596 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5597 src_width
= ft_face
->glyph
->bitmap
.width
;
5598 src_height
= ft_face
->glyph
->bitmap
.rows
;
5600 if ( render_mode
== FT_RENDER_MODE_LCD
)
5608 rgb_interval
= src_pitch
;
5613 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5614 if ( x_shift
< 0 ) x_shift
= 0;
5615 if ( x_shift
+ (src_width
/ hmul
) > width
)
5616 x_shift
= width
- (src_width
/ hmul
);
5618 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5619 if ( y_shift
< 0 ) y_shift
= 0;
5620 if ( y_shift
+ (src_height
/ vmul
) > height
)
5621 y_shift
= height
- (src_height
/ vmul
);
5623 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5624 while ( src_height
)
5626 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5630 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5631 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5632 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5633 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5637 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5638 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5639 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5640 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5643 src
+= src_pitch
* vmul
;
5652 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5664 int contour
, point
= 0, first_pt
;
5665 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5666 TTPOLYGONHEADER
*pph
;
5668 DWORD pph_start
, cpfx
, type
;
5670 if(buflen
== 0) buf
= NULL
;
5672 if (needsTransform
&& buf
) {
5673 pFT_Outline_Transform(outline
, &transMat
);
5676 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5678 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5681 pph
->dwType
= TT_POLYGON_TYPE
;
5682 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5684 needed
+= sizeof(*pph
);
5686 while(point
<= outline
->contours
[contour
]) {
5687 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5688 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5689 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5693 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5696 } while(point
<= outline
->contours
[contour
] &&
5697 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5698 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5699 /* At the end of a contour Windows adds the start point, but
5701 if(point
> outline
->contours
[contour
] &&
5702 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5704 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5706 } else if(point
<= outline
->contours
[contour
] &&
5707 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5708 /* add closing pt for bezier */
5710 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5718 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5721 pph
->cb
= needed
- pph_start
;
5727 /* Convert the quadratic Beziers to cubic Beziers.
5728 The parametric eqn for a cubic Bezier is, from PLRM:
5729 r(t) = at^3 + bt^2 + ct + r0
5730 with the control points:
5735 A quadratic Bezier has the form:
5736 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5738 So equating powers of t leads to:
5739 r1 = 2/3 p1 + 1/3 p0
5740 r2 = 2/3 p1 + 1/3 p2
5741 and of course r0 = p0, r3 = p2
5744 int contour
, point
= 0, first_pt
;
5745 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5746 TTPOLYGONHEADER
*pph
;
5748 DWORD pph_start
, cpfx
, type
;
5749 FT_Vector cubic_control
[4];
5750 if(buflen
== 0) buf
= NULL
;
5752 if (needsTransform
&& buf
) {
5753 pFT_Outline_Transform(outline
, &transMat
);
5756 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5758 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5761 pph
->dwType
= TT_POLYGON_TYPE
;
5762 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5764 needed
+= sizeof(*pph
);
5766 while(point
<= outline
->contours
[contour
]) {
5767 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5768 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5769 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5772 if(type
== TT_PRIM_LINE
) {
5774 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5778 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5781 /* FIXME: Possible optimization in endpoint calculation
5782 if there are two consecutive curves */
5783 cubic_control
[0] = outline
->points
[point
-1];
5784 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5785 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5786 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5787 cubic_control
[0].x
>>= 1;
5788 cubic_control
[0].y
>>= 1;
5790 if(point
+1 > outline
->contours
[contour
])
5791 cubic_control
[3] = outline
->points
[first_pt
];
5793 cubic_control
[3] = outline
->points
[point
+1];
5794 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5795 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5796 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5797 cubic_control
[3].x
>>= 1;
5798 cubic_control
[3].y
>>= 1;
5801 /* r1 = 1/3 p0 + 2/3 p1
5802 r2 = 1/3 p2 + 2/3 p1 */
5803 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5804 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5805 cubic_control
[2] = cubic_control
[1];
5806 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5807 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5808 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5809 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5811 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5812 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5813 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5818 } while(point
<= outline
->contours
[contour
] &&
5819 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5820 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5821 /* At the end of a contour Windows adds the start point,
5822 but only for Beziers and we've already done that.
5824 if(point
<= outline
->contours
[contour
] &&
5825 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5826 /* This is the closing pt of a bezier, but we've already
5827 added it, so just inc point and carry on */
5834 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5837 pph
->cb
= needed
- pph_start
;
5843 FIXME("Unsupported format %d\n", format
);
5849 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5851 FT_Face ft_face
= font
->ft_face
;
5852 FT_WinFNT_HeaderRec winfnt_header
;
5853 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5854 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5855 font
->potm
->otmSize
= size
;
5857 #define TM font->potm->otmTextMetrics
5858 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5860 TM
.tmHeight
= winfnt_header
.pixel_height
;
5861 TM
.tmAscent
= winfnt_header
.ascent
;
5862 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5863 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5864 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5865 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5866 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5867 TM
.tmWeight
= winfnt_header
.weight
;
5869 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5870 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5871 TM
.tmFirstChar
= winfnt_header
.first_char
;
5872 TM
.tmLastChar
= winfnt_header
.last_char
;
5873 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5874 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5875 TM
.tmItalic
= winfnt_header
.italic
;
5876 TM
.tmUnderlined
= font
->underline
;
5877 TM
.tmStruckOut
= font
->strikeout
;
5878 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5879 TM
.tmCharSet
= winfnt_header
.charset
;
5883 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5884 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5885 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5886 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5887 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5888 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5889 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5890 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5892 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5893 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5895 TM
.tmLastChar
= 255;
5896 TM
.tmDefaultChar
= 32;
5897 TM
.tmBreakChar
= 32;
5898 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5899 TM
.tmUnderlined
= font
->underline
;
5900 TM
.tmStruckOut
= font
->strikeout
;
5901 /* NB inverted meaning of TMPF_FIXED_PITCH */
5902 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5903 TM
.tmCharSet
= font
->charset
;
5911 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5913 double scale_x
, scale_y
;
5917 scale_x
= (double)font
->aveWidth
;
5918 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5921 scale_x
= font
->scale_y
;
5923 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5924 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5926 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5927 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5929 SCALE_Y(ptm
->tmHeight
);
5930 SCALE_Y(ptm
->tmAscent
);
5931 SCALE_Y(ptm
->tmDescent
);
5932 SCALE_Y(ptm
->tmInternalLeading
);
5933 SCALE_Y(ptm
->tmExternalLeading
);
5934 SCALE_Y(ptm
->tmOverhang
);
5936 SCALE_X(ptm
->tmAveCharWidth
);
5937 SCALE_X(ptm
->tmMaxCharWidth
);
5943 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5945 double scale_x
, scale_y
;
5949 scale_x
= (double)font
->aveWidth
;
5950 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5953 scale_x
= font
->scale_y
;
5955 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5956 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5958 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5960 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5961 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5963 SCALE_Y(potm
->otmAscent
);
5964 SCALE_Y(potm
->otmDescent
);
5965 SCALE_Y(potm
->otmLineGap
);
5966 SCALE_Y(potm
->otmsCapEmHeight
);
5967 SCALE_Y(potm
->otmsXHeight
);
5968 SCALE_Y(potm
->otmrcFontBox
.top
);
5969 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5970 SCALE_X(potm
->otmrcFontBox
.left
);
5971 SCALE_X(potm
->otmrcFontBox
.right
);
5972 SCALE_Y(potm
->otmMacAscent
);
5973 SCALE_Y(potm
->otmMacDescent
);
5974 SCALE_Y(potm
->otmMacLineGap
);
5975 SCALE_X(potm
->otmptSubscriptSize
.x
);
5976 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5977 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5978 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5979 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5980 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5981 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5982 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5983 SCALE_Y(potm
->otmsStrikeoutSize
);
5984 SCALE_Y(potm
->otmsStrikeoutPosition
);
5985 SCALE_Y(potm
->otmsUnderscoreSize
);
5986 SCALE_Y(potm
->otmsUnderscorePosition
);
5992 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5996 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
5998 /* Make sure that the font has sane width/height ratio */
6001 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6003 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6008 *ptm
= font
->potm
->otmTextMetrics
;
6009 scale_font_metrics(font
, ptm
);
6013 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6017 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6019 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6025 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6028 FT_Face ft_face
= font
->ft_face
;
6029 UINT needed
, lenfam
, lensty
;
6031 TT_HoriHeader
*pHori
;
6032 TT_Postscript
*pPost
;
6033 FT_Fixed x_scale
, y_scale
;
6034 WCHAR
*family_nameW
, *style_nameW
;
6035 static const WCHAR spaceW
[] = {' ', '\0'};
6037 INT ascent
, descent
;
6039 TRACE("font=%p\n", font
);
6041 if(!FT_IS_SCALABLE(ft_face
))
6044 needed
= sizeof(*font
->potm
);
6046 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6047 family_nameW
= strdupW(font
->name
);
6049 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6051 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6052 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6053 style_nameW
, lensty
/sizeof(WCHAR
));
6055 /* These names should be read from the TT name table */
6057 /* length of otmpFamilyName */
6060 /* length of otmpFaceName */
6061 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6062 needed
+= lenfam
; /* just the family name */
6064 needed
+= lenfam
+ lensty
; /* family + " " + style */
6067 /* length of otmpStyleName */
6070 /* length of otmpFullName */
6071 needed
+= lenfam
+ lensty
;
6074 x_scale
= ft_face
->size
->metrics
.x_scale
;
6075 y_scale
= ft_face
->size
->metrics
.y_scale
;
6077 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6079 FIXME("Can't find OS/2 table - not TT font?\n");
6083 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6085 FIXME("Can't find HHEA table - not TT font?\n");
6089 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6091 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",
6092 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6093 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6094 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6095 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6096 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6098 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6099 font
->potm
->otmSize
= needed
;
6101 #define TM font->potm->otmTextMetrics
6103 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6104 ascent
= pHori
->Ascender
;
6105 descent
= -pHori
->Descender
;
6107 ascent
= pOS2
->usWinAscent
;
6108 descent
= pOS2
->usWinDescent
;
6112 TM
.tmAscent
= font
->yMax
;
6113 TM
.tmDescent
= -font
->yMin
;
6114 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6116 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6117 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6118 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6119 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6122 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6125 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6127 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6128 ((ascent
+ descent
) -
6129 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6131 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6132 if (TM
.tmAveCharWidth
== 0) {
6133 TM
.tmAveCharWidth
= 1;
6135 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6136 TM
.tmWeight
= FW_REGULAR
;
6137 if (font
->fake_bold
)
6138 TM
.tmWeight
= FW_BOLD
;
6141 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6143 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6144 TM
.tmWeight
= pOS2
->usWeightClass
;
6146 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6147 TM
.tmWeight
= pOS2
->usWeightClass
;
6150 TM
.tmDigitizedAspectX
= 300;
6151 TM
.tmDigitizedAspectY
= 300;
6152 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6153 * symbol range to 0 - f0ff
6156 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6161 case 1257: /* Baltic */
6162 TM
.tmLastChar
= 0xf8fd;
6165 TM
.tmLastChar
= 0xf0ff;
6167 TM
.tmBreakChar
= 0x20;
6168 TM
.tmDefaultChar
= 0x1f;
6172 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6173 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6175 if(pOS2
->usFirstCharIndex
<= 1)
6176 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6177 else if (pOS2
->usFirstCharIndex
> 0xff)
6178 TM
.tmBreakChar
= 0x20;
6180 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6181 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6183 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6184 TM
.tmUnderlined
= font
->underline
;
6185 TM
.tmStruckOut
= font
->strikeout
;
6187 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6188 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6189 (pOS2
->version
== 0xFFFFU
||
6190 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6191 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6193 TM
.tmPitchAndFamily
= 0;
6195 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6197 case PAN_FAMILY_SCRIPT
:
6198 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6201 case PAN_FAMILY_DECORATIVE
:
6202 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6207 case PAN_FAMILY_TEXT_DISPLAY
:
6208 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6209 /* which is clearly not what the panose spec says. */
6211 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6212 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6213 TM
.tmPitchAndFamily
= FF_MODERN
;
6216 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6221 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6224 case PAN_SERIF_COVE
:
6225 case PAN_SERIF_OBTUSE_COVE
:
6226 case PAN_SERIF_SQUARE_COVE
:
6227 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6228 case PAN_SERIF_SQUARE
:
6229 case PAN_SERIF_THIN
:
6230 case PAN_SERIF_BONE
:
6231 case PAN_SERIF_EXAGGERATED
:
6232 case PAN_SERIF_TRIANGLE
:
6233 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6236 case PAN_SERIF_NORMAL_SANS
:
6237 case PAN_SERIF_OBTUSE_SANS
:
6238 case PAN_SERIF_PERP_SANS
:
6239 case PAN_SERIF_FLARED
:
6240 case PAN_SERIF_ROUNDED
:
6241 TM
.tmPitchAndFamily
|= FF_SWISS
;
6248 if(FT_IS_SCALABLE(ft_face
))
6249 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6251 if(FT_IS_SFNT(ft_face
))
6253 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6254 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6256 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6259 TM
.tmCharSet
= font
->charset
;
6261 font
->potm
->otmFiller
= 0;
6262 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6263 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6264 font
->potm
->otmfsType
= pOS2
->fsType
;
6265 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6266 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6267 font
->potm
->otmItalicAngle
= 0; /* POST table */
6268 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6269 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6270 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6271 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6272 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6273 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6274 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6275 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6276 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6277 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6278 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6279 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6280 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6281 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6282 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6283 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6284 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6285 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6286 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6287 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6288 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6289 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6290 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6291 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6293 font
->potm
->otmsUnderscoreSize
= 0;
6294 font
->potm
->otmsUnderscorePosition
= 0;
6296 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6297 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6301 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6302 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6303 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6304 strcpyW((WCHAR
*)cp
, family_nameW
);
6306 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6307 strcpyW((WCHAR
*)cp
, style_nameW
);
6309 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6310 strcpyW((WCHAR
*)cp
, family_nameW
);
6311 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6312 strcatW((WCHAR
*)cp
, spaceW
);
6313 strcatW((WCHAR
*)cp
, style_nameW
);
6314 cp
+= lenfam
+ lensty
;
6317 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6318 strcpyW((WCHAR
*)cp
, family_nameW
);
6319 strcatW((WCHAR
*)cp
, spaceW
);
6320 strcatW((WCHAR
*)cp
, style_nameW
);
6324 HeapFree(GetProcessHeap(), 0, style_nameW
);
6325 HeapFree(GetProcessHeap(), 0, family_nameW
);
6329 /*************************************************************
6330 * freetype_GetGlyphOutline
6332 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6333 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6335 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6340 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6341 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6345 EnterCriticalSection( &freetype_cs
);
6346 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6347 LeaveCriticalSection( &freetype_cs
);
6351 /*************************************************************
6352 * freetype_GetTextMetrics
6354 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6356 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6361 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6362 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6366 EnterCriticalSection( &freetype_cs
);
6367 ret
= get_text_metrics( physdev
->font
, metrics
);
6368 LeaveCriticalSection( &freetype_cs
);
6372 /*************************************************************
6373 * freetype_GetOutlineTextMetrics
6375 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6377 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6382 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6383 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6386 TRACE("font=%p\n", physdev
->font
);
6388 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6391 EnterCriticalSection( &freetype_cs
);
6393 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6395 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6397 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6398 scale_outline_font_metrics(physdev
->font
, potm
);
6400 ret
= physdev
->font
->potm
->otmSize
;
6402 LeaveCriticalSection( &freetype_cs
);
6406 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6408 HFONTLIST
*hfontlist
;
6409 child
->font
= alloc_font();
6410 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6411 if(!child
->font
->ft_face
)
6413 free_font(child
->font
);
6418 child
->font
->font_desc
= font
->font_desc
;
6419 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6420 child
->font
->orientation
= font
->orientation
;
6421 child
->font
->scale_y
= font
->scale_y
;
6422 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6423 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6424 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6425 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6426 child
->font
->base_font
= font
;
6427 list_add_head(&child_font_list
, &child
->font
->entry
);
6428 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6432 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6435 CHILD_FONT
*child_font
;
6438 font
= font
->base_font
;
6440 *linked_font
= font
;
6442 if((*glyph
= get_glyph_index(font
, c
)))
6444 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6448 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6450 if(!child_font
->font
)
6451 if(!load_child_font(font
, child_font
))
6454 if(!child_font
->font
->ft_face
)
6456 g
= get_glyph_index(child_font
->font
, c
);
6457 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6461 *linked_font
= child_font
->font
;
6468 /*************************************************************
6469 * freetype_GetCharWidth
6471 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6473 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6476 FT_UInt glyph_index
;
6477 GdiFont
*linked_font
;
6478 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6482 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6483 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6486 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6489 EnterCriticalSection( &freetype_cs
);
6490 for(c
= firstChar
; c
<= lastChar
; c
++) {
6491 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6492 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6493 &gm
, 0, NULL
, &identity
);
6494 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6496 LeaveCriticalSection( &freetype_cs
);
6500 /*************************************************************
6501 * freetype_GetCharABCWidths
6503 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6505 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6508 FT_UInt glyph_index
;
6509 GdiFont
*linked_font
;
6510 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6514 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6515 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6518 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6521 EnterCriticalSection( &freetype_cs
);
6523 for(c
= firstChar
; c
<= lastChar
; c
++) {
6524 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6525 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6526 &gm
, 0, NULL
, &identity
);
6527 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6528 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6529 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6530 FONT_GM(linked_font
,glyph_index
)->bbx
;
6532 LeaveCriticalSection( &freetype_cs
);
6536 /*************************************************************
6537 * freetype_GetCharABCWidthsI
6539 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6541 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6544 FT_UInt glyph_index
;
6545 GdiFont
*linked_font
;
6546 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6550 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6551 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6554 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6558 EnterCriticalSection( &freetype_cs
);
6560 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6562 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6563 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6564 &gm
, 0, NULL
, &identity
);
6565 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6566 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6567 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6568 - FONT_GM(linked_font
,c
)->bbx
;
6571 for(c
= 0; c
< count
; c
++) {
6572 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6573 &gm
, 0, NULL
, &identity
);
6574 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6575 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6576 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6577 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6580 LeaveCriticalSection( &freetype_cs
);
6584 /*************************************************************
6585 * freetype_GetTextExtentExPoint
6587 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6588 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6590 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6595 FT_UInt glyph_index
;
6596 GdiFont
*linked_font
;
6597 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6601 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6602 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6605 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6608 EnterCriticalSection( &freetype_cs
);
6611 get_text_metrics( physdev
->font
, &tm
);
6612 size
->cy
= tm
.tmHeight
;
6614 for(idx
= 0; idx
< count
; idx
++) {
6615 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6616 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6617 &gm
, 0, NULL
, &identity
);
6618 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6620 if (! pnfit
|| ext
<= max_ext
) {
6630 LeaveCriticalSection( &freetype_cs
);
6631 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6635 /*************************************************************
6636 * freetype_GetTextExtentExPointI
6638 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6639 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6641 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6646 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6650 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6651 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6654 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6657 EnterCriticalSection( &freetype_cs
);
6660 get_text_metrics(physdev
->font
, &tm
);
6661 size
->cy
= tm
.tmHeight
;
6663 for(idx
= 0; idx
< count
; idx
++) {
6664 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6665 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6667 if (! pnfit
|| ext
<= max_ext
) {
6677 LeaveCriticalSection( &freetype_cs
);
6678 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6682 /*************************************************************
6683 * freetype_GetFontData
6685 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6687 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6691 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6692 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6695 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6696 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6697 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6699 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6702 /*************************************************************
6703 * freetype_GetTextFace
6705 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6708 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6712 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6713 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6716 n
= strlenW(physdev
->font
->name
) + 1;
6719 lstrcpynW(str
, physdev
->font
->name
, count
);
6725 /*************************************************************
6726 * freetype_GetTextCharsetInfo
6728 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6730 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6734 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6735 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6737 if (fs
) *fs
= physdev
->font
->fs
;
6738 return physdev
->font
->charset
;
6741 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6743 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6744 struct list
*first_hfont
;
6748 EnterCriticalSection( &freetype_cs
);
6749 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6750 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6751 if(font
== linked_font
)
6752 *new_hfont
= dc
->hFont
;
6755 first_hfont
= list_head(&linked_font
->hfontlist
);
6756 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6758 LeaveCriticalSection( &freetype_cs
);
6762 /* Retrieve a list of supported Unicode ranges for a given font.
6763 * Can be called with NULL gs to calculate the buffer size. Returns
6764 * the number of ranges found.
6766 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6768 DWORD num_ranges
= 0;
6770 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6773 FT_ULong char_code
, char_code_prev
;
6776 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6778 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6779 face
->num_glyphs
, glyph_code
, char_code
);
6781 if (!glyph_code
) return 0;
6785 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6786 gs
->ranges
[0].cGlyphs
= 0;
6787 gs
->cGlyphsSupported
= 0;
6793 if (char_code
< char_code_prev
)
6795 ERR("expected increasing char code from FT_Get_Next_Char\n");
6798 if (char_code
- char_code_prev
> 1)
6803 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6804 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6805 gs
->cGlyphsSupported
++;
6810 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6811 gs
->cGlyphsSupported
++;
6813 char_code_prev
= char_code
;
6814 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6818 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6823 /*************************************************************
6824 * freetype_GetFontUnicodeRanges
6826 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6828 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6829 DWORD size
, num_ranges
;
6833 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6834 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6837 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6838 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6841 glyphset
->cbThis
= size
;
6842 glyphset
->cRanges
= num_ranges
;
6843 glyphset
->flAccel
= 0;
6848 /*************************************************************
6849 * freetype_FontIsLinked
6851 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6853 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6858 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6859 return dev
->funcs
->pFontIsLinked( dev
);
6863 EnterCriticalSection( &freetype_cs
);
6864 ret
= !list_empty(&physdev
->font
->child_fonts
);
6865 LeaveCriticalSection( &freetype_cs
);
6869 static BOOL
is_hinting_enabled(void)
6871 /* Use the >= 2.2.0 function if available */
6872 if(pFT_Get_TrueType_Engine_Type
)
6874 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6875 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6877 #ifdef FT_DRIVER_HAS_HINTER
6882 /* otherwise if we've been compiled with < 2.2.0 headers
6883 use the internal macro */
6884 mod
= pFT_Get_Module(library
, "truetype");
6885 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6893 static BOOL
is_subpixel_rendering_enabled( void )
6895 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6896 return pFT_Library_SetLcdFilter
&&
6897 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6903 /*************************************************************************
6904 * GetRasterizerCaps (GDI32.@)
6906 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6908 static int hinting
= -1;
6909 static int subpixel
= -1;
6913 hinting
= is_hinting_enabled();
6914 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6917 if ( subpixel
== -1 )
6919 subpixel
= is_subpixel_rendering_enabled();
6920 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6923 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6924 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6926 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6927 lprs
->nLanguageID
= 0;
6931 /*************************************************************
6932 * freetype_GdiRealizationInfo
6934 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
6936 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6937 realization_info_t
*info
= ptr
;
6941 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
6942 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
6945 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
6948 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
6951 info
->cache_num
= physdev
->font
->cache_num
;
6952 info
->unknown2
= -1;
6956 /*************************************************************************
6957 * Kerning support for TrueType fonts
6959 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6961 struct TT_kern_table
6967 struct TT_kern_subtable
6976 USHORT horizontal
: 1;
6978 USHORT cross_stream
: 1;
6979 USHORT override
: 1;
6980 USHORT reserved1
: 4;
6986 struct TT_format0_kern_subtable
6990 USHORT entrySelector
;
7001 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7002 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7003 const USHORT
*glyph_to_char
,
7004 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7007 const struct TT_kern_pair
*tt_kern_pair
;
7009 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7011 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7013 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7014 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7015 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7017 if (!kern_pair
|| !cPairs
)
7020 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7022 nPairs
= min(nPairs
, cPairs
);
7024 for (i
= 0; i
< nPairs
; i
++)
7026 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7027 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7028 /* this algorithm appears to better match what Windows does */
7029 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7030 if (kern_pair
->iKernAmount
< 0)
7032 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7033 kern_pair
->iKernAmount
-= font
->ppem
;
7035 else if (kern_pair
->iKernAmount
> 0)
7037 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7038 kern_pair
->iKernAmount
+= font
->ppem
;
7040 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7042 TRACE("left %u right %u value %d\n",
7043 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7047 TRACE("copied %u entries\n", nPairs
);
7051 /*************************************************************
7052 * freetype_GetKerningPairs
7054 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7058 const struct TT_kern_table
*tt_kern_table
;
7059 const struct TT_kern_subtable
*tt_kern_subtable
;
7061 USHORT
*glyph_to_char
;
7063 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7065 if (!(font
= physdev
->font
))
7067 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7068 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7072 EnterCriticalSection( &freetype_cs
);
7073 if (font
->total_kern_pairs
!= (DWORD
)-1)
7075 if (cPairs
&& kern_pair
)
7077 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7078 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7080 else cPairs
= font
->total_kern_pairs
;
7082 LeaveCriticalSection( &freetype_cs
);
7086 font
->total_kern_pairs
= 0;
7088 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7090 if (length
== GDI_ERROR
)
7092 TRACE("no kerning data in the font\n");
7093 LeaveCriticalSection( &freetype_cs
);
7097 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7100 WARN("Out of memory\n");
7101 LeaveCriticalSection( &freetype_cs
);
7105 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7107 /* build a glyph index to char code map */
7108 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7111 WARN("Out of memory allocating a glyph index to char code map\n");
7112 HeapFree(GetProcessHeap(), 0, buf
);
7113 LeaveCriticalSection( &freetype_cs
);
7117 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7123 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7125 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7126 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7130 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7132 /* FIXME: This doesn't match what Windows does: it does some fancy
7133 * things with duplicate glyph index to char code mappings, while
7134 * we just avoid overriding existing entries.
7136 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7137 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7139 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7146 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7147 for (n
= 0; n
<= 65535; n
++)
7148 glyph_to_char
[n
] = (USHORT
)n
;
7151 tt_kern_table
= buf
;
7152 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7153 TRACE("version %u, nTables %u\n",
7154 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7156 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7158 for (i
= 0; i
< nTables
; i
++)
7160 struct TT_kern_subtable tt_kern_subtable_copy
;
7162 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7163 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7164 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7166 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7167 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7168 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7170 /* According to the TrueType specification this is the only format
7171 * that will be properly interpreted by Windows and OS/2
7173 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7175 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7177 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7178 glyph_to_char
, NULL
, 0);
7179 font
->total_kern_pairs
+= new_chunk
;
7181 if (!font
->kern_pairs
)
7182 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7183 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7185 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7186 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7188 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7189 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7192 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7194 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7197 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7198 HeapFree(GetProcessHeap(), 0, buf
);
7200 if (cPairs
&& kern_pair
)
7202 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7203 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7205 else cPairs
= font
->total_kern_pairs
;
7207 LeaveCriticalSection( &freetype_cs
);
7211 static const struct gdi_dc_funcs freetype_funcs
=
7213 NULL
, /* pAbortDoc */
7214 NULL
, /* pAbortPath */
7215 NULL
, /* pAlphaBlend */
7216 NULL
, /* pAngleArc */
7219 NULL
, /* pBeginPath */
7220 NULL
, /* pBlendImage */
7221 NULL
, /* pChoosePixelFormat */
7223 NULL
, /* pCloseFigure */
7224 NULL
, /* pCopyBitmap */
7225 NULL
, /* pCreateBitmap */
7226 NULL
, /* pCreateCompatibleDC */
7227 freetype_CreateDC
, /* pCreateDC */
7228 NULL
, /* pDeleteBitmap */
7229 freetype_DeleteDC
, /* pDeleteDC */
7230 NULL
, /* pDeleteObject */
7231 NULL
, /* pDescribePixelFormat */
7232 NULL
, /* pDeviceCapabilities */
7233 NULL
, /* pEllipse */
7235 NULL
, /* pEndPage */
7236 NULL
, /* pEndPath */
7237 freetype_EnumFonts
, /* pEnumFonts */
7238 NULL
, /* pEnumICMProfiles */
7239 NULL
, /* pExcludeClipRect */
7240 NULL
, /* pExtDeviceMode */
7241 NULL
, /* pExtEscape */
7242 NULL
, /* pExtFloodFill */
7243 NULL
, /* pExtSelectClipRgn */
7244 NULL
, /* pExtTextOut */
7245 NULL
, /* pFillPath */
7246 NULL
, /* pFillRgn */
7247 NULL
, /* pFlattenPath */
7248 freetype_FontIsLinked
, /* pFontIsLinked */
7249 NULL
, /* pFrameRgn */
7250 NULL
, /* pGdiComment */
7251 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7252 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7253 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7254 freetype_GetCharWidth
, /* pGetCharWidth */
7255 NULL
, /* pGetDeviceCaps */
7256 NULL
, /* pGetDeviceGammaRamp */
7257 freetype_GetFontData
, /* pGetFontData */
7258 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7259 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7260 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7261 NULL
, /* pGetICMProfile */
7262 NULL
, /* pGetImage */
7263 freetype_GetKerningPairs
, /* pGetKerningPairs */
7264 NULL
, /* pGetNearestColor */
7265 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7266 NULL
, /* pGetPixel */
7267 NULL
, /* pGetPixelFormat */
7268 NULL
, /* pGetSystemPaletteEntries */
7269 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7270 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7271 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7272 freetype_GetTextFace
, /* pGetTextFace */
7273 freetype_GetTextMetrics
, /* pGetTextMetrics */
7274 NULL
, /* pGradientFill */
7275 NULL
, /* pIntersectClipRect */
7276 NULL
, /* pInvertRgn */
7278 NULL
, /* pModifyWorldTransform */
7280 NULL
, /* pOffsetClipRgn */
7281 NULL
, /* pOffsetViewportOrg */
7282 NULL
, /* pOffsetWindowOrg */
7283 NULL
, /* pPaintRgn */
7286 NULL
, /* pPolyBezier */
7287 NULL
, /* pPolyBezierTo */
7288 NULL
, /* pPolyDraw */
7289 NULL
, /* pPolyPolygon */
7290 NULL
, /* pPolyPolyline */
7291 NULL
, /* pPolygon */
7292 NULL
, /* pPolyline */
7293 NULL
, /* pPolylineTo */
7294 NULL
, /* pPutImage */
7295 NULL
, /* pRealizeDefaultPalette */
7296 NULL
, /* pRealizePalette */
7297 NULL
, /* pRectangle */
7298 NULL
, /* pResetDC */
7299 NULL
, /* pRestoreDC */
7300 NULL
, /* pRoundRect */
7302 NULL
, /* pScaleViewportExt */
7303 NULL
, /* pScaleWindowExt */
7304 NULL
, /* pSelectBitmap */
7305 NULL
, /* pSelectBrush */
7306 NULL
, /* pSelectClipPath */
7307 freetype_SelectFont
, /* pSelectFont */
7308 NULL
, /* pSelectPalette */
7309 NULL
, /* pSelectPen */
7310 NULL
, /* pSetArcDirection */
7311 NULL
, /* pSetBkColor */
7312 NULL
, /* pSetBkMode */
7313 NULL
, /* pSetDCBrushColor */
7314 NULL
, /* pSetDCPenColor */
7315 NULL
, /* pSetDIBColorTable */
7316 NULL
, /* pSetDIBitsToDevice */
7317 NULL
, /* pSetDeviceClipping */
7318 NULL
, /* pSetDeviceGammaRamp */
7319 NULL
, /* pSetLayout */
7320 NULL
, /* pSetMapMode */
7321 NULL
, /* pSetMapperFlags */
7322 NULL
, /* pSetPixel */
7323 NULL
, /* pSetPixelFormat */
7324 NULL
, /* pSetPolyFillMode */
7325 NULL
, /* pSetROP2 */
7326 NULL
, /* pSetRelAbs */
7327 NULL
, /* pSetStretchBltMode */
7328 NULL
, /* pSetTextAlign */
7329 NULL
, /* pSetTextCharacterExtra */
7330 NULL
, /* pSetTextColor */
7331 NULL
, /* pSetTextJustification */
7332 NULL
, /* pSetViewportExt */
7333 NULL
, /* pSetViewportOrg */
7334 NULL
, /* pSetWindowExt */
7335 NULL
, /* pSetWindowOrg */
7336 NULL
, /* pSetWorldTransform */
7337 NULL
, /* pStartDoc */
7338 NULL
, /* pStartPage */
7339 NULL
, /* pStretchBlt */
7340 NULL
, /* pStretchDIBits */
7341 NULL
, /* pStrokeAndFillPath */
7342 NULL
, /* pStrokePath */
7343 NULL
, /* pSwapBuffers */
7344 NULL
, /* pUnrealizePalette */
7345 NULL
, /* pWidenPath */
7346 /* OpenGL not supported */
7349 #else /* HAVE_FREETYPE */
7351 /*************************************************************************/
7353 BOOL
WineEngInit(void)
7357 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7362 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7364 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7368 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7370 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7374 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7376 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7380 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7385 /*************************************************************************
7386 * GetRasterizerCaps (GDI32.@)
7388 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7390 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7392 lprs
->nLanguageID
= 0;
7396 #endif /* HAVE_FREETYPE */