2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font
);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType
;
144 static FT_Library library
= 0;
151 static FT_Version_t FT_Version
;
152 static DWORD FT_SimpleVersion
;
154 static void *ft_handle
= NULL
;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face
);
158 MAKE_FUNCPTR(FT_Get_Char_Index
);
159 MAKE_FUNCPTR(FT_Get_First_Char
);
160 MAKE_FUNCPTR(FT_Get_Module
);
161 MAKE_FUNCPTR(FT_Get_Next_Char
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
166 MAKE_FUNCPTR(FT_Init_FreeType
);
167 MAKE_FUNCPTR(FT_Library_Version
);
168 MAKE_FUNCPTR(FT_Load_Glyph
);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
170 MAKE_FUNCPTR(FT_Matrix_Multiply
);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix
);
176 MAKE_FUNCPTR(FT_New_Face
);
177 MAKE_FUNCPTR(FT_New_Memory_Face
);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
179 MAKE_FUNCPTR(FT_Outline_Transform
);
180 MAKE_FUNCPTR(FT_Outline_Translate
);
181 MAKE_FUNCPTR(FT_Render_Glyph
);
182 MAKE_FUNCPTR(FT_Select_Charmap
);
183 MAKE_FUNCPTR(FT_Set_Charmap
);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
185 MAKE_FUNCPTR(FT_Vector_Transform
);
186 MAKE_FUNCPTR(FT_Vector_Unit
);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent
);
195 MAKE_FUNCPTR(FcFontList
);
196 MAKE_FUNCPTR(FcFontSetDestroy
);
197 MAKE_FUNCPTR(FcInit
);
198 MAKE_FUNCPTR(FcObjectSetAdd
);
199 MAKE_FUNCPTR(FcObjectSetCreate
);
200 MAKE_FUNCPTR(FcObjectSetDestroy
);
201 MAKE_FUNCPTR(FcPatternCreate
);
202 MAKE_FUNCPTR(FcPatternDestroy
);
203 MAKE_FUNCPTR(FcPatternGetBool
);
204 MAKE_FUNCPTR(FcPatternGetString
);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading
;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height
, width
;
249 FT_Pos size
, x_ppem
, y_ppem
;
255 NEWTEXTMETRICEXW ntm
;
259 typedef struct tagFace
{
265 DWORD font_data_size
;
269 FT_Fixed font_version
;
272 Bitmap_Size size
; /* set if face is a bitmap */
273 BOOL external
; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily
*family
;
275 /* Cached data for Enum */
276 struct enum_data
*cached_enum_data
;
279 typedef struct tagFamily
{
281 const WCHAR
*FamilyName
;
282 const WCHAR
*EnglishName
;
284 struct list
*replacement
;
289 INT adv
; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST
{
322 struct list hfontlist
;
323 OUTLINETEXTMETRICW
*potm
;
324 DWORD total_kern_pairs
;
325 KERNINGPAIR
*kern_pairs
;
326 struct list child_fonts
;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping
*mapping
;
353 const WCHAR
*font_name
;
358 struct enum_charset_element
{
361 WCHAR name
[LF_FACESIZE
];
364 struct enum_charset_list
{
366 struct enum_charset_element element
[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
373 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list
= LIST_INIT(child_font_list
);
376 static struct list system_links
= LIST_INIT(system_links
);
378 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
380 static struct list font_list
= LIST_INIT(font_list
);
382 struct freetype_physdev
384 struct gdi_physdev dev
;
388 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
390 return (struct freetype_physdev
*)dev
;
393 static const struct gdi_dc_funcs freetype_funcs
;
395 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR
* const SystemFontValues
[] = {
422 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial
[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR
*default_serif_list
[] =
450 bitstream_vera_serif
,
454 static const WCHAR
*default_fixed_list
[] =
458 bitstream_vera_sans_mono
,
462 static const WCHAR
*default_sans_list
[] =
475 typedef struct tagFontSubst
{
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value
[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value
[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value
[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 static struct list mappings_list
= LIST_INIT( mappings_list
);
513 static CRITICAL_SECTION freetype_cs
;
514 static CRITICAL_SECTION_DEBUG critsect_debug
=
517 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
518 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback
= FALSE
;
527 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
528 static BOOL
get_outline_text_metrics(GdiFont
*font
);
529 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
531 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
547 * FIXEDFON.FON FixedSys
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
589 GSUB_ScriptRecord ScriptRecord
[1];
595 } GSUB_LangSysRecord
;
600 GSUB_LangSysRecord LangSysRecord
[1];
604 WORD LookupOrder
; /* Reserved */
605 WORD ReqFeatureIndex
;
607 WORD FeatureIndex
[1];
613 } GSUB_FeatureRecord
;
617 GSUB_FeatureRecord FeatureRecord
[1];
621 WORD FeatureParams
; /* Reserved */
623 WORD LookupListIndex
[1];
642 } GSUB_CoverageFormat1
;
647 WORD StartCoverageIndex
;
653 GSUB_RangeRecord RangeRecord
[1];
654 } GSUB_CoverageFormat2
;
657 WORD SubstFormat
; /* = 1 */
660 } GSUB_SingleSubstFormat1
;
663 WORD SubstFormat
; /* = 2 */
667 }GSUB_SingleSubstFormat2
;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
674 static char cached_path
[MAX_PATH
];
675 static const char *wine
= "/Wine", *fonts
= "/Fonts";
677 if(*cached_path
) return cached_path
;
679 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
682 WARN("can't create cached data folder\n");
685 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
688 WARN("can't create cached data path\n");
692 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
694 ERR("Could not create full path\n");
698 strcat(cached_path
, wine
);
700 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
702 WARN("Couldn't mkdir %s\n", cached_path
);
706 strcat(cached_path
, fonts
);
707 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
709 WARN("Couldn't mkdir %s\n", cached_path
);
716 /******************************************************************
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path
)
734 const char *filename
;
738 unsigned int size
, max_size
;
741 TRACE("path %s\n", path
);
743 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
746 WARN("failed to get ref\n");
750 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
757 TRACE("unable to open resource fork\n");
764 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
767 CloseResFile(res_ref
);
771 out_dir
= find_cache_dir();
773 filename
= strrchr(path
, '/');
774 if(!filename
) filename
= path
;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
785 unsigned short *num_faces_ptr
, num_faces
, face
;
788 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
790 fond
= Get1IndResource(fond_res
, idx
);
792 TRACE("got fond resource %d\n", idx
);
795 fam_rec
= *(FamRec
**)fond
;
796 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
797 num_faces
= GET_BE_WORD(*num_faces_ptr
);
799 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
800 TRACE("num faces %04x\n", num_faces
);
801 for(face
= 0; face
< num_faces
; face
++, assoc
++)
804 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
805 unsigned short size
, font_id
;
808 size
= GET_BE_WORD(assoc
->fontSize
);
809 font_id
= GET_BE_WORD(assoc
->fontID
);
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
816 TRACE("trying to load sfnt id %04x\n", font_id
);
817 sfnt
= GetResource(sfnt_res
, font_id
);
820 TRACE("can't get sfnt resource %04x\n", font_id
);
824 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
829 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
831 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
832 if(fd
!= -1 || errno
== EEXIST
)
836 unsigned char *sfnt_data
;
839 sfnt_data
= *(unsigned char**)sfnt
;
840 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
844 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
847 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
849 ret
.array
[ret
.size
++] = output
;
853 WARN("unable to create %s\n", output
);
854 HeapFree(GetProcessHeap(), 0, output
);
857 ReleaseResource(sfnt
);
860 ReleaseResource(fond
);
863 CloseResFile(res_ref
);
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL
is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed
FT_FixedFromFloat(double f
)
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
889 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
893 static const struct list
*get_face_list_from_family(const Family
*family
)
895 if (!list_empty(&family
->faces
))
896 return &family
->faces
;
898 return family
->replacement
;
901 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
906 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
907 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
909 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
912 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
914 const struct list
*face_list
;
915 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
917 face_list
= get_face_list_from_family(family
);
918 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
922 file
= strrchr(face
->file
, '/');
927 if(!strcasecmp(file
, file_nameA
))
929 HeapFree(GetProcessHeap(), 0, file_nameA
);
934 HeapFree(GetProcessHeap(), 0, file_nameA
);
938 static Family
*find_family_from_name(const WCHAR
*name
)
942 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
944 if(!strcmpiW(family
->FamilyName
, name
))
951 static Family
*find_family_from_any_name(const WCHAR
*name
)
955 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
957 if(!strcmpiW(family
->FamilyName
, name
))
959 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
966 static void DumpSubstList(void)
970 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
972 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
974 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
976 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
977 debugstr_w(psub
->to
.name
));
982 static LPWSTR
strdupW(LPCWSTR p
)
985 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
986 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
991 static LPSTR
strdupA(LPCSTR p
)
994 DWORD len
= (strlen(p
) + 1);
995 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1000 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1005 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1007 if(!strcmpiW(element
->from
.name
, from_name
) &&
1008 (element
->from
.charset
== from_charset
||
1009 element
->from
.charset
== -1))
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1020 FontSubst
*from_exist
, *to_exist
;
1022 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1024 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1026 list_remove(&from_exist
->entry
);
1027 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
1028 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
1029 HeapFree(GetProcessHeap(), 0, from_exist
);
1035 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1039 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1040 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1043 list_add_tail(subst_list
, &subst
->entry
);
1048 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1049 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1050 HeapFree(GetProcessHeap(), 0, subst
);
1054 static WCHAR
*towstr(UINT cp
, const char *str
)
1059 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1060 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1061 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1065 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1067 CHAR
*p
= strrchr(str
, ',');
1071 nc
->charset
= strtol(p
+1, NULL
, 10);
1074 nc
->name
= towstr(CP_ACP
, str
);
1077 static void LoadSubstList(void)
1081 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey
) == ERROR_SUCCESS
) {
1089 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1090 &valuelen
, &datalen
, NULL
, NULL
);
1092 valuelen
++; /* returned value doesn't include room for '\0' */
1093 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1094 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1098 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1099 &dlen
) == ERROR_SUCCESS
) {
1100 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1102 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1103 split_subst_info(&psub
->from
, value
);
1104 split_subst_info(&psub
->to
, data
);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1109 psub
->to
.charset
== DEFAULT_CHARSET
) {
1110 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1111 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1112 HeapFree(GetProcessHeap(), 0, psub
);
1114 add_font_subst(&font_subst_list
, psub
, 0);
1116 /* reset dlen and vlen */
1120 HeapFree(GetProcessHeap(), 0, data
);
1121 HeapFree(GetProcessHeap(), 0, value
);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1138 FT_UInt num_names
, name_index
;
1140 if(FT_IS_SFNT(ft_face
))
1142 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1144 for(name_index
= 0; name_index
< num_names
; name_index
++)
1146 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1148 if((name
.platform_id
== req
->platform_id
) &&
1149 (name
.encoding_id
== req
->encoding_id
) &&
1150 (name
.language_id
== req
->language_id
) &&
1151 (name
.name_id
== req
->name_id
))
1153 req
->string
= name
.string
;
1154 req
->string_len
= name
.string_len
;
1161 req
->string_len
= 0;
1165 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1170 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1171 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1172 name
.language_id
= language_id
;
1173 name
.name_id
= name_id
;
1175 if(get_name_table_entry(ft_face
, &name
))
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1181 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1183 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1184 ret
[i
] = GET_BE_WORD(*tmp
);
1187 TRACE("Got localised name %s\n", debugstr_w(ret
));
1193 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1196 LONG r
= RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, &needed
);
1197 if(r
!= ERROR_SUCCESS
) return r
;
1198 if(type
!= REG_DWORD
|| needed
!= sizeof(DWORD
)) return ERROR_BAD_CONFIGURATION
;
1199 return RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &needed
);
1202 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1204 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1207 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
)
1210 DWORD num_strikes
, max_strike_key_len
;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1218 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1219 face
->cached_enum_data
= NULL
;
1221 face
->file
= HeapAlloc(GetProcessHeap(), 0, needed
);
1222 RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, (BYTE
*)face
->file
, &needed
);
1224 face
->StyleName
= strdupW(face_name
);
1225 face
->family
= family
;
1226 face
->vertical
= (family
->FamilyName
[0] == '@');
1228 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1230 WCHAR
*fullName
= HeapAlloc(GetProcessHeap(), 0, needed
);
1231 RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, (BYTE
*)fullName
, &needed
);
1232 face
->FullName
= fullName
;
1235 face
->FullName
= NULL
;
1237 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1238 reg_load_dword(hkey_face
, face_italic_value
, &italic
);
1239 reg_load_dword(hkey_face
, face_bold_value
, &bold
);
1240 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1241 reg_load_dword(hkey_face
, face_external_value
, (DWORD
*)&face
->external
);
1243 needed
= sizeof(face
->fs
);
1244 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1246 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1248 face
->scalable
= TRUE
;
1249 memset(&face
->size
, 0, sizeof(face
->size
));
1253 face
->scalable
= FALSE
;
1254 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1255 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1256 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1257 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1258 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1262 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1266 if (italic
) face
->ntmFlags
|= NTM_ITALIC
;
1267 if (bold
) face
->ntmFlags
|= NTM_BOLD
;
1268 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1272 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1273 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1275 if(!italic
&& !bold
)
1276 list_add_head(&family
->faces
, &face
->entry
);
1278 list_add_tail(&family
->faces
, &face
->entry
);
1280 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face
, NULL
, NULL
, NULL
, &num_strikes
, &max_strike_key_len
, NULL
, NULL
,
1285 NULL
, NULL
, NULL
, NULL
);
1286 if(num_strikes
!= 0)
1288 WCHAR strike_name
[10];
1289 DWORD strike_index
= 0;
1291 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1292 while(RegEnumKeyExW(hkey_face
, strike_index
++, strike_name
, &needed
,
1293 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1296 RegOpenKeyExW(hkey_face
, strike_name
, 0, KEY_ALL_ACCESS
, &hkey_strike
);
1297 load_face(hkey_strike
, face_name
, family
);
1298 RegCloseKey(hkey_strike
);
1299 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1306 DWORD max_family_key_len
, size
;
1308 DWORD family_index
= 0;
1312 RegQueryInfoKeyW(hkey_font_cache
, NULL
, NULL
, NULL
, NULL
, &max_family_key_len
, NULL
, NULL
,
1313 NULL
, NULL
, NULL
, NULL
);
1314 family_name
= HeapAlloc(GetProcessHeap(), 0, (max_family_key_len
+ 1) * sizeof(WCHAR
));
1316 size
= max_family_key_len
+ 1;
1317 while(RegEnumKeyExW(hkey_font_cache
, family_index
++, family_name
, &size
,
1318 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1320 WCHAR
*english_family
= NULL
;
1321 DWORD face_index
= 0;
1323 DWORD max_face_key_len
;
1325 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1326 TRACE("opened family key %s\n", debugstr_w(family_name
));
1327 if(RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, NULL
, &size
) == ERROR_SUCCESS
)
1329 english_family
= HeapAlloc(GetProcessHeap(), 0, size
);
1330 RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)english_family
, &size
);
1333 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1334 family
->FamilyName
= strdupW(family_name
);
1335 family
->EnglishName
= english_family
;
1336 list_init(&family
->faces
);
1337 family
->replacement
= &family
->faces
;
1338 list_add_tail(&font_list
, &family
->entry
);
1342 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1343 subst
->from
.name
= strdupW(english_family
);
1344 subst
->from
.charset
= -1;
1345 subst
->to
.name
= strdupW(family_name
);
1346 subst
->to
.charset
= -1;
1347 add_font_subst(&font_subst_list
, subst
, 0);
1350 RegQueryInfoKeyW(hkey_family
, NULL
, NULL
, NULL
, NULL
, &max_face_key_len
, NULL
, NULL
,
1351 NULL
, NULL
, NULL
, NULL
);
1353 face_name
= HeapAlloc(GetProcessHeap(), 0, (max_face_key_len
+ 1) * sizeof(WCHAR
));
1354 size
= max_face_key_len
+ 1;
1355 while(RegEnumKeyExW(hkey_family
, face_index
++, face_name
, &size
,
1356 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1360 RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
);
1361 load_face(hkey_face
, face_name
, family
);
1362 RegCloseKey(hkey_face
);
1363 size
= max_face_key_len
+ 1;
1365 HeapFree(GetProcessHeap(), 0, face_name
);
1366 RegCloseKey(hkey_family
);
1367 size
= max_family_key_len
+ 1;
1370 HeapFree(GetProcessHeap(), 0, family_name
);
1373 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1376 HKEY hkey_wine_fonts
;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1380 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1381 if(ret
!= ERROR_SUCCESS
)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1387 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1388 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1389 RegCloseKey(hkey_wine_fonts
);
1393 static void add_face_to_cache(Face
*face
)
1395 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1396 WCHAR
*face_key_name
;
1398 create_font_cache_key(&hkey_font_cache
, NULL
);
1400 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1401 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1402 if(face
->family
->EnglishName
)
1403 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1404 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1407 face_key_name
= face
->StyleName
;
1410 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1411 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1412 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1414 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1417 HeapFree(GetProcessHeap(), 0, face_key_name
);
1419 RegSetValueExA(hkey_face
, "File Name", 0, REG_BINARY
, (BYTE
*)face
->file
, strlen(face
->file
) + 1);
1421 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1422 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1424 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1425 reg_save_dword(hkey_face
, face_italic_value
, (face
->ntmFlags
& NTM_ITALIC
) != 0);
1426 reg_save_dword(hkey_face
, face_bold_value
, (face
->ntmFlags
& NTM_BOLD
) != 0);
1427 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1428 reg_save_dword(hkey_face
, face_external_value
, face
->external
);
1430 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1434 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1435 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1436 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1437 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1438 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1439 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1441 RegCloseKey(hkey_face
);
1442 RegCloseKey(hkey_family
);
1443 RegCloseKey(hkey_font_cache
);
1446 static inline int TestStyles(DWORD flags
, DWORD styles
)
1448 return (flags
& styles
) == styles
;
1451 static int StyleOrdering(Face
*face
)
1453 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1455 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1457 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1459 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face
->family
->FamilyName
),
1464 debugstr_w(face
->StyleName
),
1470 /* Add a style of face to a font family using an ordering of the list such
1471 that regular fonts come before bold and italic, and single styles come
1472 before compound styles. */
1473 static void AddFaceToFamily(Face
*face
, Family
*family
)
1477 LIST_FOR_EACH( entry
, &family
->faces
)
1479 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1480 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1482 list_add_before( entry
, &face
->entry
);
1485 static WCHAR
*prepend_at(WCHAR
*family
)
1492 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1494 strcpyW(str
+ 1, family
);
1495 HeapFree(GetProcessHeap(), 0, family
);
1499 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1501 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1502 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1504 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID() );
1510 else if (!strcmpiW( *name
, *english
))
1512 HeapFree( GetProcessHeap(), 0, *english
);
1518 *name
= prepend_at( *name
);
1519 *english
= prepend_at( *english
);
1523 /****************************************************************
1524 * NB This function stores the ptrs to the strings to save copying.
1525 * Don't free them after calling.
1527 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1529 Family
*family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1530 family
->FamilyName
= name
;
1531 family
->EnglishName
= english_name
;
1532 list_init( &family
->faces
);
1533 family
->replacement
= &family
->faces
;
1538 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1541 WCHAR
*name
, *english_name
;
1543 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1545 family
= find_family_from_name( name
);
1549 family
= create_family( name
, english_name
);
1550 list_add_tail( &font_list
, &family
->entry
);
1554 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1555 subst
->from
.name
= strdupW( english_name
);
1556 subst
->from
.charset
= -1;
1557 subst
->to
.name
= strdupW( name
);
1558 subst
->to
.charset
= -1;
1559 add_font_subst( &font_subst_list
, subst
, 0 );
1564 HeapFree( GetProcessHeap(), 0, name
);
1565 HeapFree( GetProcessHeap(), 0, english_name
);
1572 #define ADDFONT_EXTERNAL_FONT 0x01
1573 #define ADDFONT_FORCE_BITMAP 0x02
1574 #define ADDFONT_ADD_TO_CACHE 0x04
1576 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
)
1586 struct list
*face_elem_ptr
;
1587 FT_WinFNT_HeaderRec winfnt_header
;
1588 int internal_leading
;
1590 My_FT_Bitmap_Size
*size
= NULL
;
1593 if(!FT_IS_SCALABLE(ft_face
))
1594 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1596 family
= get_family( ft_face
, vertical
);
1598 StyleW
= towstr(CP_ACP
, ft_face
->style_name
);
1600 internal_leading
= 0;
1601 memset(&fs
, 0, sizeof(fs
));
1603 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1605 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1606 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1607 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1608 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1609 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1610 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1611 if(pOS2
->version
== 0) {
1614 if(pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1615 fs
.fsCsb
[0] |= FS_LATIN1
;
1617 fs
.fsCsb
[0] |= FS_SYMBOL
;
1620 else if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1622 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1623 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1624 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1626 internal_leading
= winfnt_header
.internal_leading
;
1629 pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
);
1630 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1631 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1632 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1633 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1634 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1635 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1636 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1638 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1639 TRACE("Original font is newer so skipping this one\n");
1640 HeapFree(GetProcessHeap(), 0, StyleW
);
1643 TRACE("Replacing original with this one\n");
1644 list_remove(&face
->entry
);
1645 HeapFree(GetProcessHeap(), 0, face
->file
);
1646 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1647 HeapFree(GetProcessHeap(), 0, face
->FullName
);
1648 HeapFree(GetProcessHeap(), 0, face
);
1653 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1654 face
->cached_enum_data
= NULL
;
1655 face
->StyleName
= StyleW
;
1656 face
->FullName
= get_face_name(ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1659 face
->file
= strdupA(file
);
1660 face
->font_data_ptr
= NULL
;
1661 face
->font_data_size
= 0;
1666 face
->font_data_ptr
= font_data_ptr
;
1667 face
->font_data_size
= font_data_size
;
1669 face
->face_index
= face_index
;
1671 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1672 face
->ntmFlags
|= NTM_ITALIC
;
1673 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1674 face
->ntmFlags
|= NTM_BOLD
;
1675 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1676 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1677 face
->family
= family
;
1678 face
->vertical
= vertical
;
1679 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1682 if(FT_IS_SCALABLE(ft_face
)) {
1683 memset(&face
->size
, 0, sizeof(face
->size
));
1684 face
->scalable
= TRUE
;
1686 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1687 size
->height
, size
->width
, size
->size
>> 6,
1688 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1689 face
->size
.height
= size
->height
;
1690 face
->size
.width
= size
->width
;
1691 face
->size
.size
= size
->size
;
1692 face
->size
.x_ppem
= size
->x_ppem
;
1693 face
->size
.y_ppem
= size
->y_ppem
;
1694 face
->size
.internal_leading
= internal_leading
;
1695 face
->scalable
= FALSE
;
1698 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1700 if (!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1702 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1703 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1706 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1707 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1708 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1709 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1711 if(face
->fs
.fsCsb
[0] == 0)
1715 /* let's see if we can find any interesting cmaps */
1716 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1717 switch(ft_face
->charmaps
[i
]->encoding
) {
1718 case FT_ENCODING_UNICODE
:
1719 case FT_ENCODING_APPLE_ROMAN
:
1720 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1722 case FT_ENCODING_MS_SYMBOL
:
1723 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1731 if(flags
& ADDFONT_ADD_TO_CACHE
)
1732 add_face_to_cache(face
);
1734 AddFaceToFamily(face
, family
);
1736 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1738 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1739 debugstr_w(StyleW
));
1742 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1747 FT_Long face_index
= 0, num_faces
;
1750 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1751 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1753 #ifdef HAVE_CARBON_CARBON_H
1756 char **mac_list
= expand_mac_font(file
);
1759 BOOL had_one
= FALSE
;
1761 for(cursor
= mac_list
; *cursor
; cursor
++)
1764 AddFontToList(*cursor
, NULL
, 0, flags
);
1765 HeapFree(GetProcessHeap(), 0, *cursor
);
1767 HeapFree(GetProcessHeap(), 0, mac_list
);
1772 #endif /* HAVE_CARBON_CARBON_H */
1777 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1778 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1781 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1782 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1786 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1790 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*/
1791 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1792 pFT_Done_Face(ft_face
);
1796 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1797 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1798 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1799 pFT_Done_Face(ft_face
);
1803 if(FT_IS_SFNT(ft_face
))
1805 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1806 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1807 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
))
1809 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1810 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1811 pFT_Done_Face(ft_face
);
1815 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1816 we don't want to load these. */
1817 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1821 if(!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1823 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1824 pFT_Done_Face(ft_face
);
1830 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1831 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1832 pFT_Done_Face(ft_face
);
1836 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1838 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1839 pFT_Done_Face(ft_face
);
1843 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1846 if (FT_HAS_VERTICAL(ft_face
))
1848 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1852 num_faces
= ft_face
->num_faces
;
1853 pFT_Done_Face(ft_face
);
1854 } while(num_faces
> ++face_index
);
1858 static void DumpFontList(void)
1862 struct list
*family_elem_ptr
, *face_elem_ptr
;
1864 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1865 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1866 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1867 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1868 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1869 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1871 TRACE(" %d", face
->size
.height
);
1878 /***********************************************************
1879 * The replacement list is a way to map an entire font
1880 * family onto another family. For example adding
1882 * [HKCU\Software\Wine\Fonts\Replacements]
1883 * "Wingdings"="Winedings"
1885 * would enumerate the Winedings font both as Winedings and
1886 * Wingdings. However if a real Wingdings font is present the
1887 * replacement does not take place.
1890 static void LoadReplaceList(void)
1893 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1898 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1899 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1901 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1902 &valuelen
, &datalen
, NULL
, NULL
);
1904 valuelen
++; /* returned value doesn't include room for '\0' */
1905 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1906 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1910 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1911 &dlen
) == ERROR_SUCCESS
) {
1912 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1913 /* "NewName"="Oldname" */
1914 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1916 if(!find_family_from_any_name(value
))
1918 Family
* const family
= find_family_from_any_name(data
);
1921 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
1922 if (new_family
!= NULL
)
1924 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
1925 new_family
->FamilyName
= strdupW(value
);
1926 new_family
->EnglishName
= NULL
;
1927 list_init(&new_family
->faces
);
1928 new_family
->replacement
= &family
->faces
;
1929 list_add_tail(&font_list
, &new_family
->entry
);
1934 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
1939 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
1941 /* reset dlen and vlen */
1945 HeapFree(GetProcessHeap(), 0, data
);
1946 HeapFree(GetProcessHeap(), 0, value
);
1951 static const WCHAR
*font_links_list
[] =
1953 Lucida_Sans_Unicode
,
1954 Microsoft_Sans_Serif
,
1958 static const struct font_links_defaults_list
1960 /* Keyed off substitution for "MS Shell Dlg" */
1961 const WCHAR
*shelldlg
;
1962 /* Maximum of four substitutes, plus terminating NULL pointer */
1963 const WCHAR
*substitutes
[5];
1964 } font_links_defaults_list
[] =
1966 /* Non East-Asian */
1967 { Tahoma
, /* FIXME unverified ordering */
1968 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
1970 /* Below lists are courtesy of
1971 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1975 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
1977 /* Chinese Simplified */
1979 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
1983 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
1985 /* Chinese Traditional */
1987 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
1992 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
1994 SYSTEM_LINKS
*font_link
;
1996 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1998 if(!strcmpiW(font_link
->font_name
, name
))
2005 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2017 SYSTEM_LINKS
*font_link
;
2019 psub
= get_font_subst(&font_subst_list
, name
, -1);
2020 /* Don't store fonts that are only substitutes for other fonts */
2023 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2027 font_link
= find_font_link(name
);
2028 if (font_link
== NULL
)
2030 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2031 font_link
->font_name
= strdupW(name
);
2032 list_init(&font_link
->links
);
2033 list_add_tail(&system_links
, &font_link
->entry
);
2036 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2037 for (i
= 0; values
[i
] != NULL
; i
++)
2039 const struct list
*face_list
;
2040 CHILD_FONT
*child_font
;
2043 if (!strcmpiW(name
,value
))
2045 psub
= get_font_subst(&font_subst_list
, value
, -1);
2047 value
= psub
->to
.name
;
2048 family
= find_family_from_name(value
);
2052 /* Use first extant filename for this Family */
2053 face_list
= get_face_list_from_family(family
);
2054 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2058 file
= strrchr(face
->file
, '/');
2067 fileW
= towstr(CP_UNIXCP
, file
);
2069 face
= find_face_from_filename(fileW
, value
);
2072 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2076 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2077 child_font
->face
= face
;
2078 child_font
->font
= NULL
;
2079 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2080 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2081 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2082 list_add_tail(&font_link
->links
, &child_font
->entry
);
2084 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2085 HeapFree(GetProcessHeap(), 0, fileW
);
2091 /*************************************************************
2094 static BOOL
init_system_links(void)
2098 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2099 WCHAR
*value
, *data
;
2100 WCHAR
*entry
, *next
;
2101 SYSTEM_LINKS
*font_link
, *system_font_link
;
2102 CHILD_FONT
*child_font
;
2103 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2104 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2105 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2110 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2112 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2113 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2114 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2115 val_len
= max_val
+ 1;
2116 data_len
= max_data
;
2118 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2120 psub
= get_font_subst(&font_subst_list
, value
, -1);
2121 /* Don't store fonts that are only substitutes for other fonts */
2124 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2127 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2128 font_link
->font_name
= strdupW(value
);
2129 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2130 list_init(&font_link
->links
);
2131 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2134 CHILD_FONT
*child_font
;
2136 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2138 next
= entry
+ strlenW(entry
) + 1;
2140 face_name
= strchrW(entry
, ',');
2144 while(isspaceW(*face_name
))
2147 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2149 face_name
= psub
->to
.name
;
2151 face
= find_face_from_filename(entry
, face_name
);
2154 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2158 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2159 child_font
->face
= face
;
2160 child_font
->font
= NULL
;
2161 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2162 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2163 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2164 list_add_tail(&font_link
->links
, &child_font
->entry
);
2166 list_add_tail(&system_links
, &font_link
->entry
);
2168 val_len
= max_val
+ 1;
2169 data_len
= max_data
;
2172 HeapFree(GetProcessHeap(), 0, value
);
2173 HeapFree(GetProcessHeap(), 0, data
);
2178 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2180 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2184 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2186 const FontSubst
*psub2
;
2187 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2189 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2191 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2192 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2194 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2195 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2197 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2199 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2205 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2208 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2209 system_font_link
->font_name
= strdupW(System
);
2210 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2211 list_init(&system_font_link
->links
);
2213 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2216 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2217 child_font
->face
= face
;
2218 child_font
->font
= NULL
;
2219 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2220 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2221 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2222 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2224 font_link
= find_font_link(Tahoma
);
2225 if (font_link
!= NULL
)
2227 CHILD_FONT
*font_link_entry
;
2228 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2230 CHILD_FONT
*new_child
;
2231 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2232 new_child
->face
= font_link_entry
->face
;
2233 new_child
->font
= NULL
;
2234 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2235 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2236 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2239 list_add_tail(&system_links
, &system_font_link
->entry
);
2243 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2246 struct dirent
*dent
;
2247 char path
[MAX_PATH
];
2249 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2251 dir
= opendir(dirname
);
2253 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2256 while((dent
= readdir(dir
)) != NULL
) {
2257 struct stat statbuf
;
2259 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2262 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2264 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2266 if(stat(path
, &statbuf
) == -1)
2268 WARN("Can't stat %s\n", debugstr_a(path
));
2271 if(S_ISDIR(statbuf
.st_mode
))
2272 ReadFontDir(path
, external_fonts
);
2275 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2276 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2277 AddFontToList(path
, NULL
, 0, addfont_flags
);
2284 static void load_fontconfig_fonts(void)
2286 #ifdef SONAME_LIBFONTCONFIG
2287 void *fc_handle
= NULL
;
2296 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2298 TRACE("Wine cannot find the fontconfig library (%s).\n",
2299 SONAME_LIBFONTCONFIG
);
2302 #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;}
2303 LOAD_FUNCPTR(FcConfigGetCurrent
);
2304 LOAD_FUNCPTR(FcFontList
);
2305 LOAD_FUNCPTR(FcFontSetDestroy
);
2306 LOAD_FUNCPTR(FcInit
);
2307 LOAD_FUNCPTR(FcObjectSetAdd
);
2308 LOAD_FUNCPTR(FcObjectSetCreate
);
2309 LOAD_FUNCPTR(FcObjectSetDestroy
);
2310 LOAD_FUNCPTR(FcPatternCreate
);
2311 LOAD_FUNCPTR(FcPatternDestroy
);
2312 LOAD_FUNCPTR(FcPatternGetBool
);
2313 LOAD_FUNCPTR(FcPatternGetString
);
2316 if(!pFcInit()) return;
2318 config
= pFcConfigGetCurrent();
2319 pat
= pFcPatternCreate();
2320 os
= pFcObjectSetCreate();
2321 pFcObjectSetAdd(os
, FC_FILE
);
2322 pFcObjectSetAdd(os
, FC_SCALABLE
);
2323 fontset
= pFcFontList(config
, pat
, os
);
2324 if(!fontset
) return;
2325 for(i
= 0; i
< fontset
->nfont
; i
++) {
2328 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2330 TRACE("fontconfig: %s\n", file
);
2332 /* We're just interested in OT/TT fonts for now, so this hack just
2333 picks up the scalable fonts without extensions .pf[ab] to save time
2334 loading every other font */
2336 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2338 TRACE("not scalable\n");
2342 len
= strlen( file
);
2343 if(len
< 4) continue;
2344 ext
= &file
[ len
- 3 ];
2345 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2346 AddFontToList(file
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2348 pFcFontSetDestroy(fontset
);
2349 pFcObjectSetDestroy(os
);
2350 pFcPatternDestroy(pat
);
2356 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2359 const char *data_dir
= wine_get_data_dir();
2361 if (!data_dir
) data_dir
= wine_get_build_dir();
2368 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2370 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2372 strcpy(unix_name
, data_dir
);
2373 strcat(unix_name
, "/fonts/");
2375 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2377 EnterCriticalSection( &freetype_cs
);
2378 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2379 LeaveCriticalSection( &freetype_cs
);
2380 HeapFree(GetProcessHeap(), 0, unix_name
);
2385 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2387 static const WCHAR slashW
[] = {'\\','\0'};
2389 WCHAR windowsdir
[MAX_PATH
];
2392 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2393 strcatW(windowsdir
, fontsW
);
2394 strcatW(windowsdir
, slashW
);
2395 strcatW(windowsdir
, file
);
2396 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2397 EnterCriticalSection( &freetype_cs
);
2398 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2399 LeaveCriticalSection( &freetype_cs
);
2400 HeapFree(GetProcessHeap(), 0, unixname
);
2405 static void load_system_fonts(void)
2408 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2409 const WCHAR
* const *value
;
2411 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2414 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2415 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2416 strcatW(windowsdir
, fontsW
);
2417 for(value
= SystemFontValues
; *value
; value
++) {
2418 dlen
= sizeof(data
);
2419 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2423 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2424 if((unixname
= wine_get_unix_file_name(pathW
))) {
2425 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2426 HeapFree(GetProcessHeap(), 0, unixname
);
2429 load_font_from_data_dir(data
);
2436 /*************************************************************
2438 * This adds registry entries for any externally loaded fonts
2439 * (fonts from fontconfig or FontDirs). It also deletes entries
2440 * of no longer existing fonts.
2443 static void update_reg_entries(void)
2445 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2450 struct list
*family_elem_ptr
, *face_elem_ptr
;
2452 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2453 static const WCHAR spaceW
[] = {' ', '\0'};
2456 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2457 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2458 ERR("Can't create Windows font reg key\n");
2462 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2463 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2464 ERR("Can't create Windows font reg key\n");
2468 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2469 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2470 ERR("Can't create external font reg key\n");
2474 /* enumerate the fonts and add external ones to the two keys */
2476 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2477 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2478 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2479 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2480 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2481 if(!face
->external
) continue;
2483 if (!(face
->ntmFlags
& NTM_REGULAR
))
2484 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2485 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2486 strcpyW(valueW
, family
->FamilyName
);
2487 if(len
!= len_fam
) {
2488 strcatW(valueW
, spaceW
);
2489 strcatW(valueW
, face
->StyleName
);
2491 strcatW(valueW
, TrueType
);
2493 file
= wine_get_dos_file_name(face
->file
);
2495 len
= strlenW(file
) + 1;
2498 if((path
= strrchr(face
->file
, '/')) == NULL
)
2502 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2504 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2505 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2507 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2508 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2509 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2511 HeapFree(GetProcessHeap(), 0, file
);
2512 HeapFree(GetProcessHeap(), 0, valueW
);
2516 if(external_key
) RegCloseKey(external_key
);
2517 if(win9x_key
) RegCloseKey(win9x_key
);
2518 if(winnt_key
) RegCloseKey(winnt_key
);
2522 static void delete_external_font_keys(void)
2524 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2525 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2529 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2530 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2531 ERR("Can't create Windows font reg key\n");
2535 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2536 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2537 ERR("Can't create Windows font reg key\n");
2541 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2542 ERR("Can't create external font reg key\n");
2546 /* Delete all external fonts added last time */
2548 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2549 &valuelen
, &datalen
, NULL
, NULL
);
2550 valuelen
++; /* returned value doesn't include room for '\0' */
2551 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2552 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2554 dlen
= datalen
* sizeof(WCHAR
);
2557 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2558 &dlen
) == ERROR_SUCCESS
) {
2560 RegDeleteValueW(winnt_key
, valueW
);
2561 RegDeleteValueW(win9x_key
, valueW
);
2562 /* reset dlen and vlen */
2566 HeapFree(GetProcessHeap(), 0, data
);
2567 HeapFree(GetProcessHeap(), 0, valueW
);
2569 /* Delete the old external fonts key */
2570 RegCloseKey(external_key
);
2571 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2574 if(win9x_key
) RegCloseKey(win9x_key
);
2575 if(winnt_key
) RegCloseKey(winnt_key
);
2578 /*************************************************************
2579 * WineEngAddFontResourceEx
2582 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2588 if (ft_handle
) /* do it only if we have freetype up and running */
2593 FIXME("Ignoring flags %x\n", flags
);
2595 if((unixname
= wine_get_unix_file_name(file
)))
2597 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2599 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2600 EnterCriticalSection( &freetype_cs
);
2601 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2602 LeaveCriticalSection( &freetype_cs
);
2603 HeapFree(GetProcessHeap(), 0, unixname
);
2605 if (!ret
&& !strchrW(file
, '\\')) {
2606 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2607 ret
= load_font_from_winfonts_dir(file
);
2609 /* Try in datadir/fonts (or builddir/fonts),
2610 * needed for Magic the Gathering Online
2612 ret
= load_font_from_data_dir(file
);
2619 /*************************************************************
2620 * WineEngAddFontMemResourceEx
2623 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2627 if (ft_handle
) /* do it only if we have freetype up and running */
2629 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2631 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2632 memcpy(pFontCopy
, pbFont
, cbFont
);
2634 EnterCriticalSection( &freetype_cs
);
2635 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2636 LeaveCriticalSection( &freetype_cs
);
2640 TRACE("AddFontToList failed\n");
2641 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2644 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2645 * For now return something unique but quite random
2647 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2648 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2655 /*************************************************************
2656 * WineEngRemoveFontResourceEx
2659 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2662 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2666 static const struct nls_update_font_list
2668 UINT ansi_cp
, oem_cp
;
2669 const char *oem
, *fixed
, *system
;
2670 const char *courier
, *serif
, *small
, *sserif
;
2671 /* these are for font substitutes */
2672 const char *shelldlg
, *tmsrmn
;
2673 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2677 const char *from
, *to
;
2678 } arial_0
, courier_new_0
, times_new_roman_0
;
2679 } nls_update_font_list
[] =
2681 /* Latin 1 (United States) */
2682 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2683 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2684 "Tahoma","Times New Roman",
2685 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2688 /* Latin 1 (Multilingual) */
2689 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2690 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2691 "Tahoma","Times New Roman", /* FIXME unverified */
2692 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2695 /* Eastern Europe */
2696 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2697 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2698 "Tahoma","Times New Roman", /* FIXME unverified */
2699 "Fixedsys,238", "System,238",
2700 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2701 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2702 { "Arial CE,0", "Arial,238" },
2703 { "Courier New CE,0", "Courier New,238" },
2704 { "Times New Roman CE,0", "Times New Roman,238" }
2707 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2708 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2709 "Tahoma","Times New Roman", /* FIXME unverified */
2710 "Fixedsys,204", "System,204",
2711 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2712 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2713 { "Arial Cyr,0", "Arial,204" },
2714 { "Courier New Cyr,0", "Courier New,204" },
2715 { "Times New Roman Cyr,0", "Times New Roman,204" }
2718 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2719 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2720 "Tahoma","Times New Roman", /* FIXME unverified */
2721 "Fixedsys,161", "System,161",
2722 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2723 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2724 { "Arial Greek,0", "Arial,161" },
2725 { "Courier New Greek,0", "Courier New,161" },
2726 { "Times New Roman Greek,0", "Times New Roman,161" }
2729 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2730 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2731 "Tahoma","Times New Roman", /* FIXME unverified */
2732 "Fixedsys,162", "System,162",
2733 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2734 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2735 { "Arial Tur,0", "Arial,162" },
2736 { "Courier New Tur,0", "Courier New,162" },
2737 { "Times New Roman Tur,0", "Times New Roman,162" }
2740 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2741 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2742 "Tahoma","Times New Roman", /* FIXME unverified */
2743 "Fixedsys,177", "System,177",
2744 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2745 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2749 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2750 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2751 "Tahoma","Times New Roman", /* FIXME unverified */
2752 "Fixedsys,178", "System,178",
2753 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2754 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2758 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2759 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2760 "Tahoma","Times New Roman", /* FIXME unverified */
2761 "Fixedsys,186", "System,186",
2762 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2763 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2764 { "Arial Baltic,0", "Arial,186" },
2765 { "Courier New Baltic,0", "Courier New,186" },
2766 { "Times New Roman Baltic,0", "Times New Roman,186" }
2769 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2770 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2771 "Tahoma","Times New Roman", /* FIXME unverified */
2772 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2776 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2777 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2778 "Tahoma","Times New Roman", /* FIXME unverified */
2779 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2783 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2784 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2785 "MS UI Gothic","MS Serif",
2786 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2789 /* Chinese Simplified */
2790 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2791 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2792 "SimSun", "NSimSun",
2793 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2797 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2798 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2800 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2803 /* Chinese Traditional */
2804 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2805 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2806 "PMingLiU", "MingLiU",
2807 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2812 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2814 return ( ansi_cp
== 932 /* CP932 for Japanese */
2815 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2816 || ansi_cp
== 949 /* CP949 for Korean */
2817 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2820 static inline HKEY
create_fonts_NT_registry_key(void)
2824 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2825 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2829 static inline HKEY
create_fonts_9x_registry_key(void)
2833 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2834 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2838 static inline HKEY
create_config_fonts_registry_key(void)
2842 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2843 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2847 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2849 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2850 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2851 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2852 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2855 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2858 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2860 RegDeleteValueA(hkey
, name
);
2863 static void update_font_info(void)
2865 char buf
[40], cpbuf
[40];
2868 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2871 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2874 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2875 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2876 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2877 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2878 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2880 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2881 if (is_dbcs_ansi_cp(ansi_cp
))
2882 use_default_fallback
= TRUE
;
2885 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2887 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2892 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2894 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2896 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2899 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2903 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2904 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2906 hkey
= create_config_fonts_registry_key();
2907 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2908 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2909 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2912 hkey
= create_fonts_NT_registry_key();
2913 add_font_list(hkey
, &nls_update_font_list
[i
]);
2916 hkey
= create_fonts_9x_registry_key();
2917 add_font_list(hkey
, &nls_update_font_list
[i
]);
2920 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2922 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2923 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2924 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2925 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2927 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2928 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2929 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2930 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2931 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2932 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2933 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2934 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2936 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2937 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2938 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2946 /* Delete the FontSubstitutes from other locales */
2947 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2949 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2950 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2951 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2957 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2960 static BOOL
init_freetype(void)
2962 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2965 "Wine cannot find the FreeType font library. To enable Wine to\n"
2966 "use TrueType fonts please install a version of FreeType greater than\n"
2967 "or equal to 2.0.5.\n"
2968 "http://www.freetype.org\n");
2972 #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;}
2974 LOAD_FUNCPTR(FT_Done_Face
)
2975 LOAD_FUNCPTR(FT_Get_Char_Index
)
2976 LOAD_FUNCPTR(FT_Get_First_Char
)
2977 LOAD_FUNCPTR(FT_Get_Module
)
2978 LOAD_FUNCPTR(FT_Get_Next_Char
)
2979 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2980 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2981 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2982 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
2983 LOAD_FUNCPTR(FT_Init_FreeType
)
2984 LOAD_FUNCPTR(FT_Library_Version
)
2985 LOAD_FUNCPTR(FT_Load_Glyph
)
2986 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
2987 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2988 #ifndef FT_MULFIX_INLINED
2989 LOAD_FUNCPTR(FT_MulFix
)
2991 LOAD_FUNCPTR(FT_New_Face
)
2992 LOAD_FUNCPTR(FT_New_Memory_Face
)
2993 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2994 LOAD_FUNCPTR(FT_Outline_Transform
)
2995 LOAD_FUNCPTR(FT_Outline_Translate
)
2996 LOAD_FUNCPTR(FT_Render_Glyph
)
2997 LOAD_FUNCPTR(FT_Select_Charmap
)
2998 LOAD_FUNCPTR(FT_Set_Charmap
)
2999 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3000 LOAD_FUNCPTR(FT_Vector_Transform
)
3001 LOAD_FUNCPTR(FT_Vector_Unit
)
3003 /* Don't warn if these ones are missing */
3004 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3005 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3006 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3009 if(pFT_Init_FreeType(&library
) != 0) {
3010 ERR("Can't init FreeType library\n");
3011 wine_dlclose(ft_handle
, NULL
, 0);
3015 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3017 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3018 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3019 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3020 ((FT_Version
.patch
) & 0x0000ff);
3022 font_driver
= &freetype_funcs
;
3027 "Wine cannot find certain functions that it needs inside the FreeType\n"
3028 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3029 "FreeType to at least version 2.1.4.\n"
3030 "http://www.freetype.org\n");
3031 wine_dlclose(ft_handle
, NULL
, 0);
3036 static void init_font_list(void)
3038 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3039 static const WCHAR pathW
[] = {'P','a','t','h',0};
3041 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3042 WCHAR windowsdir
[MAX_PATH
];
3045 const char *data_dir
;
3047 delete_external_font_keys();
3049 /* load the system bitmap fonts */
3050 load_system_fonts();
3052 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3053 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3054 strcatW(windowsdir
, fontsW
);
3055 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3057 ReadFontDir(unixname
, FALSE
);
3058 HeapFree(GetProcessHeap(), 0, unixname
);
3061 /* load the system truetype fonts */
3062 data_dir
= wine_get_data_dir();
3063 if (!data_dir
) data_dir
= wine_get_build_dir();
3064 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3066 strcpy(unixname
, data_dir
);
3067 strcat(unixname
, "/fonts/");
3068 ReadFontDir(unixname
, TRUE
);
3069 HeapFree(GetProcessHeap(), 0, unixname
);
3072 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3073 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3074 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3076 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3077 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3078 &hkey
) == ERROR_SUCCESS
)
3080 LPWSTR data
, valueW
;
3081 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3082 &valuelen
, &datalen
, NULL
, NULL
);
3084 valuelen
++; /* returned value doesn't include room for '\0' */
3085 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3086 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3089 dlen
= datalen
* sizeof(WCHAR
);
3091 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3092 &dlen
) == ERROR_SUCCESS
)
3094 if(data
[0] && (data
[1] == ':'))
3096 if((unixname
= wine_get_unix_file_name(data
)))
3098 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3099 HeapFree(GetProcessHeap(), 0, unixname
);
3102 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3104 WCHAR pathW
[MAX_PATH
];
3105 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3108 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3109 if((unixname
= wine_get_unix_file_name(pathW
)))
3111 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3112 HeapFree(GetProcessHeap(), 0, unixname
);
3115 load_font_from_data_dir(data
);
3117 /* reset dlen and vlen */
3122 HeapFree(GetProcessHeap(), 0, data
);
3123 HeapFree(GetProcessHeap(), 0, valueW
);
3127 load_fontconfig_fonts();
3129 /* then look in any directories that we've specified in the config file */
3130 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3131 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3137 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3139 len
+= sizeof(WCHAR
);
3140 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3141 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3143 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3144 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3145 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3146 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3150 LPSTR next
= strchr( ptr
, ':' );
3151 if (next
) *next
++ = 0;
3152 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3153 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3155 strcpy( unixname
, home
);
3156 strcat( unixname
, ptr
+ 1 );
3157 ReadFontDir( unixname
, TRUE
);
3158 HeapFree( GetProcessHeap(), 0, unixname
);
3161 ReadFontDir( ptr
, TRUE
);
3164 HeapFree( GetProcessHeap(), 0, valueA
);
3166 HeapFree( GetProcessHeap(), 0, valueW
);
3172 /* Mac default font locations. */
3173 ReadFontDir( "/Library/Fonts", TRUE
);
3174 ReadFontDir( "/Network/Library/Fonts", TRUE
);
3175 ReadFontDir( "/System/Library/Fonts", TRUE
);
3176 if ((home
= getenv( "HOME" )))
3178 unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(home
)+15 );
3179 strcpy( unixname
, home
);
3180 strcat( unixname
, "/Library/Fonts" );
3181 ReadFontDir( unixname
, TRUE
);
3182 HeapFree( GetProcessHeap(), 0, unixname
);
3187 static BOOL
move_to_front(const WCHAR
*name
)
3189 Family
*family
, *cursor2
;
3190 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3192 if(!strcmpiW(family
->FamilyName
, name
))
3194 list_remove(&family
->entry
);
3195 list_add_head(&font_list
, &family
->entry
);
3202 static BOOL
set_default(const WCHAR
**name_list
)
3206 if (move_to_front(*name_list
)) return TRUE
;
3213 static void reorder_font_list(void)
3215 set_default( default_serif_list
);
3216 set_default( default_fixed_list
);
3217 set_default( default_sans_list
);
3220 /*************************************************************
3223 * Initialize FreeType library and create a list of available faces
3225 BOOL
WineEngInit(void)
3227 HKEY hkey_font_cache
;
3231 /* update locale dependent font info in registry */
3234 if(!init_freetype()) return FALSE
;
3236 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3238 ERR("Failed to create font mutex\n");
3241 WaitForSingleObject(font_mutex
, INFINITE
);
3243 create_font_cache_key(&hkey_font_cache
, &disposition
);
3245 if(disposition
== REG_CREATED_NEW_KEY
)
3248 load_font_list_from_cache(hkey_font_cache
);
3250 RegCloseKey(hkey_font_cache
);
3252 reorder_font_list();
3259 if(disposition
== REG_CREATED_NEW_KEY
)
3260 update_reg_entries();
3262 init_system_links();
3264 ReleaseMutex(font_mutex
);
3269 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3272 TT_HoriHeader
*pHori
;
3276 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3277 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3279 if(height
== 0) height
= 16;
3281 /* Calc. height of EM square:
3283 * For +ve lfHeight we have
3284 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3285 * Re-arranging gives:
3286 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3288 * For -ve lfHeight we have
3290 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3291 * with il = winAscent + winDescent - units_per_em]
3296 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3297 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3298 pHori
->Ascender
- pHori
->Descender
);
3300 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3301 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3309 static struct font_mapping
*map_font_file( const char *name
)
3311 struct font_mapping
*mapping
;
3315 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3316 if (fstat( fd
, &st
) == -1) goto error
;
3318 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3320 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3322 mapping
->refcount
++;
3327 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3330 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3333 if (mapping
->data
== MAP_FAILED
)
3335 HeapFree( GetProcessHeap(), 0, mapping
);
3338 mapping
->refcount
= 1;
3339 mapping
->dev
= st
.st_dev
;
3340 mapping
->ino
= st
.st_ino
;
3341 mapping
->size
= st
.st_size
;
3342 list_add_tail( &mappings_list
, &mapping
->entry
);
3350 static void unmap_font_file( struct font_mapping
*mapping
)
3352 if (!--mapping
->refcount
)
3354 list_remove( &mapping
->entry
);
3355 munmap( mapping
->data
, mapping
->size
);
3356 HeapFree( GetProcessHeap(), 0, mapping
);
3360 static LONG
load_VDMX(GdiFont
*, LONG
);
3362 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3369 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3373 if (!(font
->mapping
= map_font_file( face
->file
)))
3375 WARN("failed to map %s\n", debugstr_a(face
->file
));
3378 data_ptr
= font
->mapping
->data
;
3379 data_size
= font
->mapping
->size
;
3383 data_ptr
= face
->font_data_ptr
;
3384 data_size
= face
->font_data_size
;
3387 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3389 ERR("FT_New_Face rets %d\n", err
);
3393 /* set it here, as load_VDMX needs it */
3394 font
->ft_face
= ft_face
;
3396 if(FT_IS_SCALABLE(ft_face
)) {
3397 /* load the VDMX table if we have one */
3398 font
->ppem
= load_VDMX(font
, height
);
3400 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3401 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3403 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3404 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3406 font
->ppem
= height
;
3407 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3408 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3414 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3416 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3417 a single face with the requested charset. The idea is to check if
3418 the selected font supports the current ANSI codepage, if it does
3419 return the corresponding charset, else return the first charset */
3422 int acp
= GetACP(), i
;
3426 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3428 const SYSTEM_LINKS
*font_link
;
3430 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
3431 return csi
.ciCharset
;
3433 font_link
= find_font_link(family_name
);
3434 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
3435 return csi
.ciCharset
;
3438 for(i
= 0; i
< 32; i
++) {
3440 if(face
->fs
.fsCsb
[0] & fs0
) {
3441 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3443 return csi
.ciCharset
;
3446 FIXME("TCI failing on %x\n", fs0
);
3450 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3451 face
->fs
.fsCsb
[0], face
->file
);
3453 return DEFAULT_CHARSET
;
3456 static GdiFont
*alloc_font(void)
3458 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3460 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3461 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3463 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3464 ret
->total_kern_pairs
= (DWORD
)-1;
3465 ret
->kern_pairs
= NULL
;
3466 list_init(&ret
->hfontlist
);
3467 list_init(&ret
->child_fonts
);
3471 static void free_font(GdiFont
*font
)
3473 struct list
*cursor
, *cursor2
;
3476 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3478 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3479 list_remove(cursor
);
3481 free_font(child
->font
);
3482 HeapFree(GetProcessHeap(), 0, child
);
3485 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3487 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3488 DeleteObject(hfontlist
->hfont
);
3489 list_remove(&hfontlist
->entry
);
3490 HeapFree(GetProcessHeap(), 0, hfontlist
);
3493 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3494 if (font
->mapping
) unmap_font_file( font
->mapping
);
3495 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3496 HeapFree(GetProcessHeap(), 0, font
->potm
);
3497 HeapFree(GetProcessHeap(), 0, font
->name
);
3498 for (i
= 0; i
< font
->gmsize
; i
++)
3499 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3500 HeapFree(GetProcessHeap(), 0, font
->gm
);
3501 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3502 HeapFree(GetProcessHeap(), 0, font
);
3506 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3508 FT_Face ft_face
= font
->ft_face
;
3512 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3519 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3521 /* make sure value of len is the value freetype says it needs */
3524 FT_ULong needed
= 0;
3525 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3526 if( !err
&& needed
< len
) len
= needed
;
3528 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3531 TRACE("Can't find table %c%c%c%c\n",
3532 /* bytes were reversed */
3533 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3534 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3540 /*************************************************************
3543 * load the vdmx entry for the specified height
3546 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3547 ( ( (FT_ULong)_x4 << 24 ) | \
3548 ( (FT_ULong)_x3 << 16 ) | \
3549 ( (FT_ULong)_x2 << 8 ) | \
3552 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3567 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3571 BYTE devXRatio
, devYRatio
;
3572 USHORT numRecs
, numRatios
;
3573 DWORD result
, offset
= -1;
3577 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3579 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3582 /* FIXME: need the real device aspect ratio */
3586 numRecs
= GET_BE_WORD(hdr
[1]);
3587 numRatios
= GET_BE_WORD(hdr
[2]);
3589 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3590 for(i
= 0; i
< numRatios
; i
++) {
3593 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3594 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3597 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3599 if((ratio
.xRatio
== 0 &&
3600 ratio
.yStartRatio
== 0 &&
3601 ratio
.yEndRatio
== 0) ||
3602 (devXRatio
== ratio
.xRatio
&&
3603 devYRatio
>= ratio
.yStartRatio
&&
3604 devYRatio
<= ratio
.yEndRatio
))
3606 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3607 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3608 offset
= GET_BE_WORD(tmp
);
3614 FIXME("No suitable ratio found\n");
3618 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3620 BYTE startsz
, endsz
;
3623 recs
= GET_BE_WORD(group
.recs
);
3624 startsz
= group
.startsz
;
3625 endsz
= group
.endsz
;
3627 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3629 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3630 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3631 if(result
== GDI_ERROR
) {
3632 FIXME("Failed to retrieve vTable\n");
3637 for(i
= 0; i
< recs
; i
++) {
3638 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3639 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3640 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3642 if(yMax
+ -yMin
== height
) {
3645 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3648 if(yMax
+ -yMin
> height
) {
3651 goto end
; /* failed */
3653 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3654 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3655 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3656 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3662 TRACE("ppem not found for height %d\n", height
);
3666 HeapFree(GetProcessHeap(), 0, vTable
);
3672 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3674 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3675 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3676 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3677 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3678 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3681 static void calc_hash(FONT_DESC
*pfd
)
3683 DWORD hash
= 0, *ptr
, two_chars
;
3687 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3689 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3691 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3693 pwc
= (WCHAR
*)&two_chars
;
3695 *pwc
= toupperW(*pwc
);
3697 *pwc
= toupperW(*pwc
);
3701 hash
^= !pfd
->can_use_bitmap
;
3706 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3711 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3715 fd
.can_use_bitmap
= can_use_bitmap
;
3718 /* try the child list */
3719 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3720 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3721 if(!fontcmp(ret
, &fd
)) {
3722 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3723 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3724 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3725 if(hflist
->hfont
== hfont
)
3731 /* try the in-use list */
3732 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3733 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3734 if(!fontcmp(ret
, &fd
)) {
3735 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3736 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3737 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3738 if(hflist
->hfont
== hfont
)
3741 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3742 hflist
->hfont
= hfont
;
3743 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3748 /* then the unused list */
3749 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3750 while(font_elem_ptr
) {
3751 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3752 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3753 if(!fontcmp(ret
, &fd
)) {
3754 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3755 assert(list_empty(&ret
->hfontlist
));
3756 TRACE("Found %p in unused list\n", ret
);
3757 list_remove(&ret
->entry
);
3758 list_add_head(&gdi_font_list
, &ret
->entry
);
3759 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3760 hflist
->hfont
= hfont
;
3761 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3768 static void add_to_cache(GdiFont
*font
)
3770 static DWORD cache_num
= 1;
3772 font
->cache_num
= cache_num
++;
3773 list_add_head(&gdi_font_list
, &font
->entry
);
3776 /*************************************************************
3777 * create_child_font_list
3779 static BOOL
create_child_font_list(GdiFont
*font
)
3782 SYSTEM_LINKS
*font_link
;
3783 CHILD_FONT
*font_link_entry
, *new_child
;
3787 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3788 font_name
= psub
? psub
->to
.name
: font
->name
;
3789 font_link
= find_font_link(font_name
);
3790 if (font_link
!= NULL
)
3792 TRACE("found entry in system list\n");
3793 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3795 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3796 new_child
->face
= font_link_entry
->face
;
3797 new_child
->font
= NULL
;
3798 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3799 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3804 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3805 * Sans Serif. This is how asian windows get default fallbacks for fonts
3807 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3808 font
->charset
!= OEM_CHARSET
&&
3809 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3811 font_link
= find_font_link(szDefaultFallbackLink
);
3812 if (font_link
!= NULL
)
3814 TRACE("found entry in default fallback list\n");
3815 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3817 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3818 new_child
->face
= font_link_entry
->face
;
3819 new_child
->font
= NULL
;
3820 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3821 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3830 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3832 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3834 if (pFT_Set_Charmap
)
3837 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3839 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3841 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3843 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3845 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3846 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3848 switch (ft_face
->charmaps
[i
]->platform_id
)
3851 cmap_def
= ft_face
->charmaps
[i
];
3853 case 0: /* Apple Unicode */
3854 cmap0
= ft_face
->charmaps
[i
];
3856 case 1: /* Macintosh */
3857 cmap1
= ft_face
->charmaps
[i
];
3860 cmap2
= ft_face
->charmaps
[i
];
3862 case 3: /* Microsoft */
3863 cmap3
= ft_face
->charmaps
[i
];
3868 if (cmap3
) /* prefer Microsoft cmap table */
3869 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3871 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3873 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3875 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3877 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3879 return ft_err
== FT_Err_Ok
;
3882 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3886 /*************************************************************
3889 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
3890 LPCWSTR output
, const DEVMODEW
*devmode
)
3892 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
3894 if (!physdev
) return FALSE
;
3895 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
3900 /*************************************************************
3903 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
3905 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3906 HeapFree( GetProcessHeap(), 0, physdev
);
3911 /*************************************************************
3912 * freetype_SelectFont
3914 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
3916 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3918 Face
*face
, *best
, *best_bitmap
;
3919 Family
*family
, *last_resort_family
;
3920 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
3921 INT height
, width
= 0;
3922 unsigned int score
= 0, new_score
;
3923 signed int diff
= 0, newdiff
;
3924 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
3929 FontSubst
*psub
= NULL
;
3930 DC
*dc
= get_dc_ptr( dev
->hdc
);
3931 const SYSTEM_LINKS
*font_link
;
3933 if (!hfont
) /* notification that the font has been changed by another driver */
3936 physdev
->font
= NULL
;
3937 release_dc_ptr( dc
);
3941 GetObjectW( hfont
, sizeof(lf
), &lf
);
3942 lf
.lfWidth
= abs(lf
.lfWidth
);
3944 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
3946 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3947 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3948 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3951 if(dc
->GraphicsMode
== GM_ADVANCED
)
3953 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3954 /* Try to avoid not necessary glyph transformations */
3955 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3957 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3958 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3959 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3964 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3965 font scaling abilities. */
3966 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3967 dcmat
.eM21
= dcmat
.eM12
= 0;
3968 if (dc
->vport2WorldValid
)
3970 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
3971 lf
.lfOrientation
= -lf
.lfOrientation
;
3972 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
3973 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
3977 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3978 dcmat
.eM21
, dcmat
.eM22
);
3981 EnterCriticalSection( &freetype_cs
);
3983 /* check the cache first */
3984 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3985 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3989 if(list_empty(&font_list
)) /* No fonts installed */
3991 TRACE("No fonts installed\n");
3995 TRACE("not in cache\n");
3998 ret
->font_desc
.matrix
= dcmat
;
3999 ret
->font_desc
.lf
= lf
;
4000 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4001 calc_hash(&ret
->font_desc
);
4002 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4003 hflist
->hfont
= hfont
;
4004 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4006 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4007 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4008 original value lfCharSet. Note this is a special case for
4009 Symbol and doesn't happen at least for "Wingdings*" */
4011 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4012 lf
.lfCharSet
= SYMBOL_CHARSET
;
4014 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4015 switch(lf
.lfCharSet
) {
4016 case DEFAULT_CHARSET
:
4017 csi
.fs
.fsCsb
[0] = 0;
4020 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4021 csi
.fs
.fsCsb
[0] = 0;
4027 if(lf
.lfFaceName
[0] != '\0') {
4028 CHILD_FONT
*font_link_entry
;
4029 LPWSTR FaceName
= lf
.lfFaceName
;
4031 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4034 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4035 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4036 if (psub
->to
.charset
!= -1)
4037 lf
.lfCharSet
= psub
->to
.charset
;
4040 /* We want a match on name and charset or just name if
4041 charset was DEFAULT_CHARSET. If the latter then
4042 we fixup the returned charset later in get_nearest_charset
4043 where we'll either use the charset of the current ansi codepage
4044 or if that's unavailable the first charset that the font supports.
4046 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4047 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4048 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4049 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4051 font_link
= find_font_link(family
->FamilyName
);
4052 face_list
= get_face_list_from_family(family
);
4053 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4054 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4055 if (!(face
->scalable
|| can_use_bitmap
))
4057 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4059 if (font_link
!= NULL
&&
4060 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4062 if (!csi
.fs
.fsCsb
[0])
4068 /* Search by full face name. */
4069 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4070 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4071 face_list
= get_face_list_from_family(family
);
4072 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4073 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4074 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4075 (face
->scalable
|| can_use_bitmap
))
4077 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4079 font_link
= find_font_link(family
->FamilyName
);
4080 if (font_link
!= NULL
&&
4081 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4088 * Try check the SystemLink list first for a replacement font.
4089 * We may find good replacements there.
4091 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4093 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4094 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4096 TRACE("found entry in system list\n");
4097 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4099 const SYSTEM_LINKS
*links
;
4101 face
= font_link_entry
->face
;
4102 if (!(face
->scalable
|| can_use_bitmap
))
4104 family
= face
->family
;
4105 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4107 links
= find_font_link(family
->FamilyName
);
4108 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4115 psub
= NULL
; /* substitution is no more relevant */
4117 /* If requested charset was DEFAULT_CHARSET then try using charset
4118 corresponding to the current ansi codepage */
4119 if (!csi
.fs
.fsCsb
[0])
4122 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4123 FIXME("TCI failed on codepage %d\n", acp
);
4124 csi
.fs
.fsCsb
[0] = 0;
4126 lf
.lfCharSet
= csi
.ciCharset
;
4129 want_vertical
= (lf
.lfFaceName
[0] == '@');
4131 /* Face families are in the top 4 bits of lfPitchAndFamily,
4132 so mask with 0xF0 before testing */
4134 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4135 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4136 strcpyW(lf
.lfFaceName
, defFixed
);
4137 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4138 strcpyW(lf
.lfFaceName
, defSerif
);
4139 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4140 strcpyW(lf
.lfFaceName
, defSans
);
4142 strcpyW(lf
.lfFaceName
, defSans
);
4143 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4144 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4145 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4146 font_link
= find_font_link(family
->FamilyName
);
4147 face_list
= get_face_list_from_family(family
);
4148 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4149 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4150 if (!(face
->scalable
|| can_use_bitmap
))
4152 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4154 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4160 last_resort_family
= NULL
;
4161 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4162 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4163 font_link
= find_font_link(family
->FamilyName
);
4164 face_list
= get_face_list_from_family(family
);
4165 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4166 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4167 if(face
->vertical
== want_vertical
&&
4168 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4169 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4172 if(can_use_bitmap
&& !last_resort_family
)
4173 last_resort_family
= family
;
4178 if(last_resort_family
) {
4179 family
= last_resort_family
;
4180 csi
.fs
.fsCsb
[0] = 0;
4184 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4185 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4186 face_list
= get_face_list_from_family(family
);
4187 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4188 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4189 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4190 csi
.fs
.fsCsb
[0] = 0;
4191 WARN("just using first face for now\n");
4194 if(can_use_bitmap
&& !last_resort_family
)
4195 last_resort_family
= family
;
4198 if(!last_resort_family
) {
4199 FIXME("can't find a single appropriate font - bailing\n");
4205 WARN("could only find a bitmap font - this will probably look awful!\n");
4206 family
= last_resort_family
;
4207 csi
.fs
.fsCsb
[0] = 0;
4210 it
= lf
.lfItalic
? 1 : 0;
4211 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4213 height
= lf
.lfHeight
;
4215 face
= best
= best_bitmap
= NULL
;
4216 font_link
= find_font_link(family
->FamilyName
);
4217 face_list
= get_face_list_from_family(family
);
4218 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4220 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4221 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4226 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4227 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4228 new_score
= (italic
^ it
) + (bold
^ bd
);
4229 if(!best
|| new_score
<= score
)
4231 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4232 italic
, bold
, it
, bd
);
4235 if(best
->scalable
&& score
== 0) break;
4239 newdiff
= height
- (signed int)(best
->size
.height
);
4241 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4242 if(!best_bitmap
|| new_score
< score
||
4243 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4245 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4248 if(score
== 0 && diff
== 0) break;
4255 face
= best
->scalable
? best
: best_bitmap
;
4256 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4257 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4260 height
= lf
.lfHeight
;
4264 if(csi
.fs
.fsCsb
[0]) {
4265 ret
->charset
= lf
.lfCharSet
;
4266 ret
->codepage
= csi
.ciACP
;
4269 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4271 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4272 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4274 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4276 if(!face
->scalable
) {
4277 /* Windows uses integer scaling factors for bitmap fonts */
4278 INT scale
, scaled_height
;
4279 GdiFont
*cachedfont
;
4281 /* FIXME: rotation of bitmap fonts is ignored */
4282 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4284 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4285 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4286 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4287 /* As we changed the matrix, we need to search the cache for the font again,
4288 * otherwise we might explode the cache. */
4289 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4290 TRACE("Found cached font after non-scalable matrix rescale!\n");
4295 calc_hash(&ret
->font_desc
);
4297 if (height
!= 0) height
= diff
;
4298 height
+= face
->size
.height
;
4300 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4301 scaled_height
= scale
* face
->size
.height
;
4302 /* Only jump to the next height if the difference <= 25% original height */
4303 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4304 /* The jump between unscaled and doubled is delayed by 1 */
4305 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4306 ret
->scale_y
= scale
;
4308 width
= face
->size
.x_ppem
>> 6;
4309 height
= face
->size
.y_ppem
>> 6;
4313 TRACE("font scale y: %f\n", ret
->scale_y
);
4315 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4324 ret
->ntmFlags
= face
->ntmFlags
;
4326 if (ret
->charset
== SYMBOL_CHARSET
&&
4327 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4330 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4334 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4337 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4338 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4339 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4340 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4341 create_child_font_list(ret
);
4343 if (face
->vertical
) /* We need to try to load the GSUB table */
4345 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4346 if (length
!= GDI_ERROR
)
4348 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4349 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4350 TRACE("Loaded GSUB table of %i bytes\n",length
);
4354 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4361 physdev
->font
= ret
;
4363 LeaveCriticalSection( &freetype_cs
);
4364 release_dc_ptr( dc
);
4365 return ret
? hfont
: 0;
4368 static void dump_gdi_font_list(void)
4371 struct list
*elem_ptr
;
4373 TRACE("---------- gdiFont Cache ----------\n");
4374 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4375 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4376 TRACE("gdiFont=%p %s %d\n",
4377 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4380 TRACE("---------- Unused gdiFont Cache ----------\n");
4381 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4382 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4383 TRACE("gdiFont=%p %s %d\n",
4384 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4387 TRACE("---------- Child gdiFont Cache ----------\n");
4388 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4389 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4390 TRACE("gdiFont=%p %s %d\n",
4391 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4395 /*************************************************************
4396 * WineEngDestroyFontInstance
4398 * free the gdiFont associated with this handle
4401 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4406 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4410 EnterCriticalSection( &freetype_cs
);
4412 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4414 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4415 while(hfontlist_elem_ptr
) {
4416 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4417 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4418 if(hflist
->hfont
== handle
) {
4419 TRACE("removing child font %p from child list\n", gdiFont
);
4420 list_remove(&gdiFont
->entry
);
4421 LeaveCriticalSection( &freetype_cs
);
4427 TRACE("destroying hfont=%p\n", handle
);
4429 dump_gdi_font_list();
4431 font_elem_ptr
= list_head(&gdi_font_list
);
4432 while(font_elem_ptr
) {
4433 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4434 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4436 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4437 while(hfontlist_elem_ptr
) {
4438 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4439 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4440 if(hflist
->hfont
== handle
) {
4441 list_remove(&hflist
->entry
);
4442 HeapFree(GetProcessHeap(), 0, hflist
);
4446 if(list_empty(&gdiFont
->hfontlist
)) {
4447 TRACE("Moving to Unused list\n");
4448 list_remove(&gdiFont
->entry
);
4449 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4454 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4455 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4456 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4457 while(font_elem_ptr
) {
4458 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4459 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4460 TRACE("freeing %p\n", gdiFont
);
4461 list_remove(&gdiFont
->entry
);
4464 LeaveCriticalSection( &freetype_cs
);
4468 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4475 id
+= IDS_FIRST_SCRIPT
;
4476 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4477 if (!rsrc
) return 0;
4478 hMem
= LoadResource( gdi32_module
, rsrc
);
4479 if (!hMem
) return 0;
4481 p
= LockResource( hMem
);
4483 while (id
--) p
+= *p
+ 1;
4485 i
= min(LF_FACESIZE
- 1, *p
);
4486 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4492 /***************************************************
4493 * create_enum_charset_list
4495 * This function creates charset enumeration list because in DEFAULT_CHARSET
4496 * case, the ANSI codepage's charset takes precedence over other charsets.
4497 * This function works as a filter other than DEFAULT_CHARSET case.
4499 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4504 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4505 csi
.fs
.fsCsb
[0] != 0) {
4506 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4507 list
->element
[n
].charset
= csi
.ciCharset
;
4508 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4511 else { /* charset is DEFAULT_CHARSET or invalid. */
4514 /* Set the current codepage's charset as the first element. */
4516 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4517 csi
.fs
.fsCsb
[0] != 0) {
4518 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4519 list
->element
[n
].charset
= csi
.ciCharset
;
4520 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4524 /* Fill out left elements. */
4525 for (i
= 0; i
< 32; i
++) {
4527 fs
.fsCsb
[0] = 1L << i
;
4529 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4530 continue; /* skip, already added. */
4531 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4532 continue; /* skip, this is an invalid fsCsb bit. */
4534 list
->element
[n
].mask
= fs
.fsCsb
[0];
4535 list
->element
[n
].charset
= csi
.ciCharset
;
4536 load_script_name( i
, list
->element
[n
].name
);
4545 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4546 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4551 if (face
->cached_enum_data
)
4554 *pelf
= face
->cached_enum_data
->elf
;
4555 *pntm
= face
->cached_enum_data
->ntm
;
4556 *ptype
= face
->cached_enum_data
->type
;
4560 font
= alloc_font();
4562 if(face
->scalable
) {
4563 height
= -2048; /* 2048 is the most common em size */
4566 height
= face
->size
.y_ppem
>> 6;
4567 width
= face
->size
.x_ppem
>> 6;
4569 font
->scale_y
= 1.0;
4571 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4577 font
->name
= strdupW(face
->family
->FamilyName
);
4578 font
->ntmFlags
= face
->ntmFlags
;
4580 if (get_outline_text_metrics(font
))
4582 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4584 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4586 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4587 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4589 lstrcpynW(pelf
->elfFullName
,
4590 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4592 lstrcpynW(pelf
->elfStyle
,
4593 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4598 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4600 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4602 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4604 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4606 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4607 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4610 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4611 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4612 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4613 pntm
->ntmFontSig
= face
->fs
;
4615 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4617 pelf
->elfLogFont
.lfEscapement
= 0;
4618 pelf
->elfLogFont
.lfOrientation
= 0;
4619 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4620 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4621 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4622 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4623 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4624 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4625 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4626 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4627 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4628 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4629 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4632 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4633 *ptype
|= TRUETYPE_FONTTYPE
;
4634 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4635 *ptype
|= DEVICE_FONTTYPE
;
4636 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4637 *ptype
|= RASTER_FONTTYPE
;
4639 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4640 if (face
->cached_enum_data
)
4642 face
->cached_enum_data
->elf
= *pelf
;
4643 face
->cached_enum_data
->ntm
= *pntm
;
4644 face
->cached_enum_data
->type
= *ptype
;
4650 static void create_full_name(WCHAR
*full_name
, const WCHAR
*family_name
, const WCHAR
*style_name
)
4652 static const WCHAR spaceW
[] = { ' ', 0 };
4654 strcpyW(full_name
, family_name
);
4655 strcatW(full_name
, spaceW
);
4656 strcatW(full_name
, style_name
);
4659 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4661 const struct list
*face_list
, *face_elem_ptr
;
4663 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4665 face_list
= get_face_list_from_family(family
);
4666 LIST_FOR_EACH(face_elem_ptr
, face_list
)
4668 WCHAR full_family_name
[LF_FULLFACESIZE
];
4669 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4671 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4673 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4674 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4678 create_full_name(full_family_name
, family
->FamilyName
, face
->StyleName
);
4679 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4685 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
4687 WCHAR full_family_name
[LF_FULLFACESIZE
];
4689 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
4691 if (strlenW(family_name
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4693 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4694 debugstr_w(family_name
), debugstr_w(face
->StyleName
));
4698 create_full_name(full_family_name
, family_name
, face
->StyleName
);
4699 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4702 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
4703 FONTENUMPROCW proc
, LPARAM lparam
)
4706 NEWTEXTMETRICEXW ntm
;
4710 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4711 for(i
= 0; i
< list
->total
; i
++) {
4712 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4713 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4714 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4715 i
= list
->total
; /* break out of loop after enumeration */
4716 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4719 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4720 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4721 if (!elf
.elfScript
[0])
4722 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4724 /* Font Replacement */
4725 if (family
!= face
->family
)
4727 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
4728 create_full_name(elf
.elfFullName
, family
->FamilyName
, face
->StyleName
);
4730 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4731 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4732 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4733 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4734 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4735 ntm
.ntmTm
.ntmFlags
);
4736 /* release section before callback (FIXME) */
4737 LeaveCriticalSection( &freetype_cs
);
4738 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4739 EnterCriticalSection( &freetype_cs
);
4744 /*************************************************************
4745 * freetype_EnumFonts
4747 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4751 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4753 struct enum_charset_list enum_charsets
;
4757 lf
.lfCharSet
= DEFAULT_CHARSET
;
4758 lf
.lfPitchAndFamily
= 0;
4759 lf
.lfFaceName
[0] = 0;
4763 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4765 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4768 EnterCriticalSection( &freetype_cs
);
4769 if(plf
->lfFaceName
[0]) {
4771 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4774 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4775 debugstr_w(psub
->to
.name
));
4777 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4781 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4782 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4783 if(family_matches(family
, plf
)) {
4784 face_list
= get_face_list_from_family(family
);
4785 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4786 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4787 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
4788 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4793 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4794 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4795 face_list
= get_face_list_from_family(family
);
4796 face_elem_ptr
= list_head(face_list
);
4797 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4798 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4801 LeaveCriticalSection( &freetype_cs
);
4805 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4807 pt
->x
.value
= vec
->x
>> 6;
4808 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4809 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4810 pt
->y
.value
= vec
->y
>> 6;
4811 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4812 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4816 /***************************************************
4817 * According to the MSDN documentation on WideCharToMultiByte,
4818 * certain codepages cannot set the default_used parameter.
4819 * This returns TRUE if the codepage can set that parameter, false else
4820 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4822 static BOOL
codepage_sets_default_used(UINT codepage
)
4836 * GSUB Table handling functions
4839 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4841 const GSUB_CoverageFormat1
* cf1
;
4845 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4847 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4849 TRACE("Coverage Format 1, %i glyphs\n",count
);
4850 for (i
= 0; i
< count
; i
++)
4851 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4855 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4857 const GSUB_CoverageFormat2
* cf2
;
4860 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4862 count
= GET_BE_WORD(cf2
->RangeCount
);
4863 TRACE("Coverage Format 2, %i ranges\n",count
);
4864 for (i
= 0; i
< count
; i
++)
4866 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4868 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4869 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4871 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4872 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4878 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4883 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4885 const GSUB_ScriptList
*script
;
4886 const GSUB_Script
*deflt
= NULL
;
4888 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4890 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4891 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4893 const GSUB_Script
*scr
;
4896 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4897 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4899 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4901 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4907 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4911 const GSUB_LangSys
*Lang
;
4913 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4915 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4917 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4918 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4920 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4923 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4926 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4932 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4935 const GSUB_FeatureList
*feature
;
4936 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4938 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4939 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4941 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4942 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4944 const GSUB_Feature
*feat
;
4945 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4952 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4956 const GSUB_LookupList
*lookup
;
4957 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4959 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4960 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4962 const GSUB_LookupTable
*look
;
4963 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4964 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4965 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4966 if (GET_BE_WORD(look
->LookupType
) != 1)
4967 FIXME("We only handle SubType 1\n");
4972 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4974 const GSUB_SingleSubstFormat1
*ssf1
;
4975 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4976 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4977 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4979 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4980 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4981 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4983 TRACE(" Glyph 0x%x ->",glyph
);
4984 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4985 TRACE(" 0x%x\n",glyph
);
4990 const GSUB_SingleSubstFormat2
*ssf2
;
4994 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4995 offset
= GET_BE_WORD(ssf1
->Coverage
);
4996 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4997 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4998 TRACE(" Coverage index %i\n",index
);
5001 TRACE(" Glyph is 0x%x ->",glyph
);
5002 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5003 TRACE("0x%x\n",glyph
);
5012 static const char* get_opentype_script(const GdiFont
*font
)
5015 * I am not sure if this is the correct way to generate our script tag
5018 switch (font
->charset
)
5020 case ANSI_CHARSET
: return "latn";
5021 case BALTIC_CHARSET
: return "latn"; /* ?? */
5022 case CHINESEBIG5_CHARSET
: return "hani";
5023 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5024 case GB2312_CHARSET
: return "hani";
5025 case GREEK_CHARSET
: return "grek";
5026 case HANGUL_CHARSET
: return "hang";
5027 case RUSSIAN_CHARSET
: return "cyrl";
5028 case SHIFTJIS_CHARSET
: return "kana";
5029 case TURKISH_CHARSET
: return "latn"; /* ?? */
5030 case VIETNAMESE_CHARSET
: return "latn";
5031 case JOHAB_CHARSET
: return "latn"; /* ?? */
5032 case ARABIC_CHARSET
: return "arab";
5033 case HEBREW_CHARSET
: return "hebr";
5034 case THAI_CHARSET
: return "thai";
5035 default: return "latn";
5039 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5041 const GSUB_Header
*header
;
5042 const GSUB_Script
*script
;
5043 const GSUB_LangSys
*language
;
5044 const GSUB_Feature
*feature
;
5046 if (!font
->GSUB_Table
)
5049 header
= font
->GSUB_Table
;
5051 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5054 TRACE("Script not found\n");
5057 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5060 TRACE("Language not found\n");
5063 feature
= GSUB_get_feature(header
, language
, "vrt2");
5065 feature
= GSUB_get_feature(header
, language
, "vert");
5068 TRACE("vrt2/vert feature not found\n");
5071 return GSUB_apply_feature(header
, feature
, glyph
);
5074 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5078 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5079 WCHAR wc
= (WCHAR
)glyph
;
5081 BOOL
*default_used_pointer
;
5084 default_used_pointer
= NULL
;
5085 default_used
= FALSE
;
5086 if (codepage_sets_default_used(font
->codepage
))
5087 default_used_pointer
= &default_used
;
5088 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5091 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5092 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5096 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5098 if (glyph
< 0x100) glyph
+= 0xf000;
5099 /* there is a number of old pre-Unicode "broken" TTFs, which
5100 do have symbols at U+00XX instead of U+f0XX */
5101 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5102 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5104 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5109 /*************************************************************
5110 * freetype_GetGlyphIndices
5112 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5114 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5117 BOOL got_default
= FALSE
;
5121 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5122 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5125 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5127 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5132 EnterCriticalSection( &freetype_cs
);
5134 for(i
= 0; i
< count
; i
++)
5136 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5141 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5143 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5144 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5149 get_text_metrics(physdev
->font
, &textm
);
5150 default_char
= textm
.tmDefaultChar
;
5154 pgi
[i
] = default_char
;
5157 LeaveCriticalSection( &freetype_cs
);
5161 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5163 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5164 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5167 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5169 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5170 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5173 static inline BYTE
get_max_level( UINT format
)
5177 case GGO_GRAY2_BITMAP
: return 4;
5178 case GGO_GRAY4_BITMAP
: return 16;
5179 case GGO_GRAY8_BITMAP
: return 64;
5184 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5186 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5187 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5190 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5191 FT_Face ft_face
= incoming_font
->ft_face
;
5192 GdiFont
*font
= incoming_font
;
5193 FT_UInt glyph_index
;
5194 DWORD width
, height
, pitch
, needed
= 0;
5195 FT_Bitmap ft_bitmap
;
5197 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5199 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5200 double widthRatio
= 1.0;
5201 FT_Matrix transMat
= identityMat
;
5202 FT_Matrix transMatUnrotated
;
5203 BOOL needsTransform
= FALSE
;
5204 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5205 UINT original_index
;
5207 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5208 buflen
, buf
, lpmat
);
5210 TRACE("font transform %f %f %f %f\n",
5211 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5212 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5214 if(format
& GGO_GLYPH_INDEX
) {
5215 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5216 original_index
= glyph
;
5217 format
&= ~GGO_GLYPH_INDEX
;
5219 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5220 ft_face
= font
->ft_face
;
5221 original_index
= glyph_index
;
5224 if(format
& GGO_UNHINTED
) {
5225 load_flags
|= FT_LOAD_NO_HINTING
;
5226 format
&= ~GGO_UNHINTED
;
5229 /* tategaki never appears to happen to lower glyph index */
5230 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5233 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5234 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5235 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5236 font
->gmsize
* sizeof(GM
*));
5238 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5239 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5241 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5242 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5243 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5244 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5245 return 1; /* FIXME */
5249 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5250 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5252 /* Scaling factor */
5257 get_text_metrics(font
, &tm
);
5259 widthRatio
= (double)font
->aveWidth
;
5260 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5263 widthRatio
= font
->scale_y
;
5265 /* Scaling transform */
5266 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5269 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5272 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5274 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5275 needsTransform
= TRUE
;
5278 /* Slant transform */
5279 if (font
->fake_italic
) {
5282 slantMat
.xx
= (1 << 16);
5283 slantMat
.xy
= ((1 << 16) >> 2);
5285 slantMat
.yy
= (1 << 16);
5286 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5287 needsTransform
= TRUE
;
5290 /* Rotation transform */
5291 transMatUnrotated
= transMat
;
5292 if(font
->orientation
&& !tategaki
) {
5293 FT_Matrix rotationMat
;
5295 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5296 pFT_Vector_Unit(&vecAngle
, angle
);
5297 rotationMat
.xx
= vecAngle
.x
;
5298 rotationMat
.xy
= -vecAngle
.y
;
5299 rotationMat
.yx
= -rotationMat
.xy
;
5300 rotationMat
.yy
= rotationMat
.xx
;
5302 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5303 needsTransform
= TRUE
;
5306 /* World transform */
5307 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5310 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5311 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5312 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5313 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5314 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5315 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5316 needsTransform
= TRUE
;
5319 /* Extra transformation specified by caller */
5320 if (!is_identity_MAT2(lpmat
))
5323 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5324 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5325 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5326 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5327 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5328 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5329 needsTransform
= TRUE
;
5332 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5333 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5334 format
== GGO_GRAY8_BITMAP
))
5336 load_flags
|= FT_LOAD_NO_BITMAP
;
5339 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5342 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5346 if(!needsTransform
) {
5347 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5348 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5349 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5351 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5352 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5353 ft_face
->glyph
->metrics
.height
) & -64;
5354 lpgm
->gmCellIncX
= adv
;
5355 lpgm
->gmCellIncY
= 0;
5362 for(xc
= 0; xc
< 2; xc
++) {
5363 for(yc
= 0; yc
< 2; yc
++) {
5364 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5365 xc
* ft_face
->glyph
->metrics
.width
);
5366 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5367 yc
* ft_face
->glyph
->metrics
.height
;
5368 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5369 pFT_Vector_Transform(&vec
, &transMat
);
5370 if(xc
== 0 && yc
== 0) {
5371 left
= right
= vec
.x
;
5372 top
= bottom
= vec
.y
;
5374 if(vec
.x
< left
) left
= vec
.x
;
5375 else if(vec
.x
> right
) right
= vec
.x
;
5376 if(vec
.y
< bottom
) bottom
= vec
.y
;
5377 else if(vec
.y
> top
) top
= vec
.y
;
5382 right
= (right
+ 63) & -64;
5383 bottom
= bottom
& -64;
5384 top
= (top
+ 63) & -64;
5386 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5387 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5389 pFT_Vector_Transform(&vec
, &transMat
);
5390 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5391 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5393 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5395 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5396 adv
= (vec
.x
+63) >> 6;
5400 bbx
= (right
- left
) >> 6;
5401 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5402 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5403 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5404 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5406 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5407 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5408 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5410 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5411 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5413 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5414 FONT_GM(font
,original_index
)->adv
= adv
;
5415 FONT_GM(font
,original_index
)->lsb
= lsb
;
5416 FONT_GM(font
,original_index
)->bbx
= bbx
;
5417 FONT_GM(font
,original_index
)->init
= TRUE
;
5420 if(format
== GGO_METRICS
)
5422 return 1; /* FIXME */
5425 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5426 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5428 TRACE("loaded a bitmap\n");
5434 width
= lpgm
->gmBlackBoxX
;
5435 height
= lpgm
->gmBlackBoxY
;
5436 pitch
= ((width
+ 31) >> 5) << 2;
5437 needed
= pitch
* height
;
5439 if(!buf
|| !buflen
) break;
5441 switch(ft_face
->glyph
->format
) {
5442 case ft_glyph_format_bitmap
:
5444 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5445 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5446 INT h
= ft_face
->glyph
->bitmap
.rows
;
5448 memcpy(dst
, src
, w
);
5449 src
+= ft_face
->glyph
->bitmap
.pitch
;
5455 case ft_glyph_format_outline
:
5456 ft_bitmap
.width
= width
;
5457 ft_bitmap
.rows
= height
;
5458 ft_bitmap
.pitch
= pitch
;
5459 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5460 ft_bitmap
.buffer
= buf
;
5463 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5465 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5467 /* Note: FreeType will only set 'black' bits for us. */
5468 memset(buf
, 0, needed
);
5469 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5473 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5478 case GGO_GRAY2_BITMAP
:
5479 case GGO_GRAY4_BITMAP
:
5480 case GGO_GRAY8_BITMAP
:
5481 case WINE_GGO_GRAY16_BITMAP
:
5483 unsigned int max_level
, row
, col
;
5486 width
= lpgm
->gmBlackBoxX
;
5487 height
= lpgm
->gmBlackBoxY
;
5488 pitch
= (width
+ 3) / 4 * 4;
5489 needed
= pitch
* height
;
5491 if(!buf
|| !buflen
) break;
5493 max_level
= get_max_level( format
);
5495 switch(ft_face
->glyph
->format
) {
5496 case ft_glyph_format_bitmap
:
5498 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5499 INT h
= ft_face
->glyph
->bitmap
.rows
;
5501 memset( buf
, 0, needed
);
5503 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5504 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5505 src
+= ft_face
->glyph
->bitmap
.pitch
;
5510 case ft_glyph_format_outline
:
5512 ft_bitmap
.width
= width
;
5513 ft_bitmap
.rows
= height
;
5514 ft_bitmap
.pitch
= pitch
;
5515 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5516 ft_bitmap
.buffer
= buf
;
5519 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5521 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5523 memset(ft_bitmap
.buffer
, 0, buflen
);
5525 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5527 if (max_level
!= 255)
5529 for (row
= 0, start
= buf
; row
< height
; row
++)
5531 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5532 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5540 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5546 case WINE_GGO_HRGB_BITMAP
:
5547 case WINE_GGO_HBGR_BITMAP
:
5548 case WINE_GGO_VRGB_BITMAP
:
5549 case WINE_GGO_VBGR_BITMAP
:
5550 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5552 switch (ft_face
->glyph
->format
)
5554 case FT_GLYPH_FORMAT_BITMAP
:
5559 width
= lpgm
->gmBlackBoxX
;
5560 height
= lpgm
->gmBlackBoxY
;
5562 needed
= pitch
* height
;
5564 if (!buf
|| !buflen
) break;
5566 memset(buf
, 0, buflen
);
5568 src
= ft_face
->glyph
->bitmap
.buffer
;
5569 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5571 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5574 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5576 if ( src
[x
/ 8] & masks
[x
% 8] )
5577 ((unsigned int *)dst
)[x
] = ~0u;
5586 case FT_GLYPH_FORMAT_OUTLINE
:
5590 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5591 INT x_shift
, y_shift
;
5593 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5594 FT_Render_Mode render_mode
=
5595 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5596 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5598 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5600 if ( render_mode
== FT_RENDER_MODE_LCD
)
5602 lpgm
->gmBlackBoxX
+= 2;
5603 lpgm
->gmptGlyphOrigin
.x
-= 1;
5607 lpgm
->gmBlackBoxY
+= 2;
5608 lpgm
->gmptGlyphOrigin
.y
+= 1;
5612 width
= lpgm
->gmBlackBoxX
;
5613 height
= lpgm
->gmBlackBoxY
;
5615 needed
= pitch
* height
;
5617 if (!buf
|| !buflen
) break;
5619 memset(buf
, 0, buflen
);
5621 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5623 if ( needsTransform
)
5624 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5626 if ( pFT_Library_SetLcdFilter
)
5627 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5628 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5630 src
= ft_face
->glyph
->bitmap
.buffer
;
5631 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5632 src_width
= ft_face
->glyph
->bitmap
.width
;
5633 src_height
= ft_face
->glyph
->bitmap
.rows
;
5635 if ( render_mode
== FT_RENDER_MODE_LCD
)
5643 rgb_interval
= src_pitch
;
5648 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5649 if ( x_shift
< 0 ) x_shift
= 0;
5650 if ( x_shift
+ (src_width
/ hmul
) > width
)
5651 x_shift
= width
- (src_width
/ hmul
);
5653 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5654 if ( y_shift
< 0 ) y_shift
= 0;
5655 if ( y_shift
+ (src_height
/ vmul
) > height
)
5656 y_shift
= height
- (src_height
/ vmul
);
5658 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5659 while ( src_height
)
5661 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5665 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5666 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5667 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5668 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5672 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5673 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5674 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5675 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5678 src
+= src_pitch
* vmul
;
5687 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5699 int contour
, point
= 0, first_pt
;
5700 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5701 TTPOLYGONHEADER
*pph
;
5703 DWORD pph_start
, cpfx
, type
;
5705 if(buflen
== 0) buf
= NULL
;
5707 if (needsTransform
&& buf
) {
5708 pFT_Outline_Transform(outline
, &transMat
);
5711 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5713 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5716 pph
->dwType
= TT_POLYGON_TYPE
;
5717 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5719 needed
+= sizeof(*pph
);
5721 while(point
<= outline
->contours
[contour
]) {
5722 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5723 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5724 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5728 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5731 } while(point
<= outline
->contours
[contour
] &&
5732 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5733 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5734 /* At the end of a contour Windows adds the start point, but
5736 if(point
> outline
->contours
[contour
] &&
5737 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5739 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5741 } else if(point
<= outline
->contours
[contour
] &&
5742 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5743 /* add closing pt for bezier */
5745 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5753 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5756 pph
->cb
= needed
- pph_start
;
5762 /* Convert the quadratic Beziers to cubic Beziers.
5763 The parametric eqn for a cubic Bezier is, from PLRM:
5764 r(t) = at^3 + bt^2 + ct + r0
5765 with the control points:
5770 A quadratic Bezier has the form:
5771 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5773 So equating powers of t leads to:
5774 r1 = 2/3 p1 + 1/3 p0
5775 r2 = 2/3 p1 + 1/3 p2
5776 and of course r0 = p0, r3 = p2
5779 int contour
, point
= 0, first_pt
;
5780 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5781 TTPOLYGONHEADER
*pph
;
5783 DWORD pph_start
, cpfx
, type
;
5784 FT_Vector cubic_control
[4];
5785 if(buflen
== 0) buf
= NULL
;
5787 if (needsTransform
&& buf
) {
5788 pFT_Outline_Transform(outline
, &transMat
);
5791 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5793 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5796 pph
->dwType
= TT_POLYGON_TYPE
;
5797 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5799 needed
+= sizeof(*pph
);
5801 while(point
<= outline
->contours
[contour
]) {
5802 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5803 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5804 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5807 if(type
== TT_PRIM_LINE
) {
5809 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5813 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5816 /* FIXME: Possible optimization in endpoint calculation
5817 if there are two consecutive curves */
5818 cubic_control
[0] = outline
->points
[point
-1];
5819 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5820 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5821 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5822 cubic_control
[0].x
>>= 1;
5823 cubic_control
[0].y
>>= 1;
5825 if(point
+1 > outline
->contours
[contour
])
5826 cubic_control
[3] = outline
->points
[first_pt
];
5828 cubic_control
[3] = outline
->points
[point
+1];
5829 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5830 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5831 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5832 cubic_control
[3].x
>>= 1;
5833 cubic_control
[3].y
>>= 1;
5836 /* r1 = 1/3 p0 + 2/3 p1
5837 r2 = 1/3 p2 + 2/3 p1 */
5838 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5839 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5840 cubic_control
[2] = cubic_control
[1];
5841 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5842 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5843 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5844 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5846 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5847 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5848 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5853 } while(point
<= outline
->contours
[contour
] &&
5854 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5855 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5856 /* At the end of a contour Windows adds the start point,
5857 but only for Beziers and we've already done that.
5859 if(point
<= outline
->contours
[contour
] &&
5860 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5861 /* This is the closing pt of a bezier, but we've already
5862 added it, so just inc point and carry on */
5869 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5872 pph
->cb
= needed
- pph_start
;
5878 FIXME("Unsupported format %d\n", format
);
5884 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5886 FT_Face ft_face
= font
->ft_face
;
5887 FT_WinFNT_HeaderRec winfnt_header
;
5888 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5889 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5890 font
->potm
->otmSize
= size
;
5892 #define TM font->potm->otmTextMetrics
5893 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5895 TM
.tmHeight
= winfnt_header
.pixel_height
;
5896 TM
.tmAscent
= winfnt_header
.ascent
;
5897 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5898 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5899 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5900 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5901 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5902 TM
.tmWeight
= winfnt_header
.weight
;
5904 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5905 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5906 TM
.tmFirstChar
= winfnt_header
.first_char
;
5907 TM
.tmLastChar
= winfnt_header
.last_char
;
5908 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5909 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5910 TM
.tmItalic
= winfnt_header
.italic
;
5911 TM
.tmUnderlined
= font
->underline
;
5912 TM
.tmStruckOut
= font
->strikeout
;
5913 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5914 TM
.tmCharSet
= winfnt_header
.charset
;
5918 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5919 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5920 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5921 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5922 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5923 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5924 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5925 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5927 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5928 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5930 TM
.tmLastChar
= 255;
5931 TM
.tmDefaultChar
= 32;
5932 TM
.tmBreakChar
= 32;
5933 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5934 TM
.tmUnderlined
= font
->underline
;
5935 TM
.tmStruckOut
= font
->strikeout
;
5936 /* NB inverted meaning of TMPF_FIXED_PITCH */
5937 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5938 TM
.tmCharSet
= font
->charset
;
5946 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5948 double scale_x
, scale_y
;
5952 scale_x
= (double)font
->aveWidth
;
5953 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5956 scale_x
= font
->scale_y
;
5958 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5959 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5961 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5962 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5964 SCALE_Y(ptm
->tmHeight
);
5965 SCALE_Y(ptm
->tmAscent
);
5966 SCALE_Y(ptm
->tmDescent
);
5967 SCALE_Y(ptm
->tmInternalLeading
);
5968 SCALE_Y(ptm
->tmExternalLeading
);
5969 SCALE_Y(ptm
->tmOverhang
);
5971 SCALE_X(ptm
->tmAveCharWidth
);
5972 SCALE_X(ptm
->tmMaxCharWidth
);
5978 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5980 double scale_x
, scale_y
;
5984 scale_x
= (double)font
->aveWidth
;
5985 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5988 scale_x
= font
->scale_y
;
5990 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5991 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5993 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5995 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5996 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5998 SCALE_Y(potm
->otmAscent
);
5999 SCALE_Y(potm
->otmDescent
);
6000 SCALE_Y(potm
->otmLineGap
);
6001 SCALE_Y(potm
->otmsCapEmHeight
);
6002 SCALE_Y(potm
->otmsXHeight
);
6003 SCALE_Y(potm
->otmrcFontBox
.top
);
6004 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6005 SCALE_X(potm
->otmrcFontBox
.left
);
6006 SCALE_X(potm
->otmrcFontBox
.right
);
6007 SCALE_Y(potm
->otmMacAscent
);
6008 SCALE_Y(potm
->otmMacDescent
);
6009 SCALE_Y(potm
->otmMacLineGap
);
6010 SCALE_X(potm
->otmptSubscriptSize
.x
);
6011 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6012 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6013 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6014 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6015 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6016 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6017 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6018 SCALE_Y(potm
->otmsStrikeoutSize
);
6019 SCALE_Y(potm
->otmsStrikeoutPosition
);
6020 SCALE_Y(potm
->otmsUnderscoreSize
);
6021 SCALE_Y(potm
->otmsUnderscorePosition
);
6027 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6031 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6033 /* Make sure that the font has sane width/height ratio */
6036 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6038 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6043 *ptm
= font
->potm
->otmTextMetrics
;
6044 scale_font_metrics(font
, ptm
);
6048 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6052 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6054 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6060 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6063 FT_Face ft_face
= font
->ft_face
;
6064 UINT needed
, lenfam
, lensty
;
6066 TT_HoriHeader
*pHori
;
6067 TT_Postscript
*pPost
;
6068 FT_Fixed x_scale
, y_scale
;
6069 WCHAR
*family_nameW
, *style_nameW
;
6070 static const WCHAR spaceW
[] = {' ', '\0'};
6072 INT ascent
, descent
;
6074 TRACE("font=%p\n", font
);
6076 if(!FT_IS_SCALABLE(ft_face
))
6079 needed
= sizeof(*font
->potm
);
6081 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6082 family_nameW
= strdupW(font
->name
);
6084 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6086 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6087 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6088 style_nameW
, lensty
/sizeof(WCHAR
));
6090 /* These names should be read from the TT name table */
6092 /* length of otmpFamilyName */
6095 /* length of otmpFaceName */
6096 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6097 needed
+= lenfam
; /* just the family name */
6099 needed
+= lenfam
+ lensty
; /* family + " " + style */
6102 /* length of otmpStyleName */
6105 /* length of otmpFullName */
6106 needed
+= lenfam
+ lensty
;
6109 x_scale
= ft_face
->size
->metrics
.x_scale
;
6110 y_scale
= ft_face
->size
->metrics
.y_scale
;
6112 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6114 FIXME("Can't find OS/2 table - not TT font?\n");
6118 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6120 FIXME("Can't find HHEA table - not TT font?\n");
6124 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6126 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",
6127 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6128 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6129 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6130 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6131 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6133 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6134 font
->potm
->otmSize
= needed
;
6136 #define TM font->potm->otmTextMetrics
6138 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6139 ascent
= pHori
->Ascender
;
6140 descent
= -pHori
->Descender
;
6142 ascent
= pOS2
->usWinAscent
;
6143 descent
= pOS2
->usWinDescent
;
6147 TM
.tmAscent
= font
->yMax
;
6148 TM
.tmDescent
= -font
->yMin
;
6149 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6151 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6152 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6153 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6154 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6157 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6160 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6162 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6163 ((ascent
+ descent
) -
6164 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6166 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6167 if (TM
.tmAveCharWidth
== 0) {
6168 TM
.tmAveCharWidth
= 1;
6170 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6171 TM
.tmWeight
= FW_REGULAR
;
6172 if (font
->fake_bold
)
6173 TM
.tmWeight
= FW_BOLD
;
6176 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6178 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6179 TM
.tmWeight
= pOS2
->usWeightClass
;
6181 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6182 TM
.tmWeight
= pOS2
->usWeightClass
;
6185 TM
.tmDigitizedAspectX
= 300;
6186 TM
.tmDigitizedAspectY
= 300;
6187 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6188 * symbol range to 0 - f0ff
6191 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6196 case 1257: /* Baltic */
6197 TM
.tmLastChar
= 0xf8fd;
6200 TM
.tmLastChar
= 0xf0ff;
6202 TM
.tmBreakChar
= 0x20;
6203 TM
.tmDefaultChar
= 0x1f;
6207 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6208 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6210 if(pOS2
->usFirstCharIndex
<= 1)
6211 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6212 else if (pOS2
->usFirstCharIndex
> 0xff)
6213 TM
.tmBreakChar
= 0x20;
6215 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6216 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6218 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6219 TM
.tmUnderlined
= font
->underline
;
6220 TM
.tmStruckOut
= font
->strikeout
;
6222 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6223 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6224 (pOS2
->version
== 0xFFFFU
||
6225 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6226 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6228 TM
.tmPitchAndFamily
= 0;
6230 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6232 case PAN_FAMILY_SCRIPT
:
6233 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6236 case PAN_FAMILY_DECORATIVE
:
6237 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6242 case PAN_FAMILY_TEXT_DISPLAY
:
6243 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6244 /* which is clearly not what the panose spec says. */
6246 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6247 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6248 TM
.tmPitchAndFamily
= FF_MODERN
;
6251 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6256 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6259 case PAN_SERIF_COVE
:
6260 case PAN_SERIF_OBTUSE_COVE
:
6261 case PAN_SERIF_SQUARE_COVE
:
6262 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6263 case PAN_SERIF_SQUARE
:
6264 case PAN_SERIF_THIN
:
6265 case PAN_SERIF_BONE
:
6266 case PAN_SERIF_EXAGGERATED
:
6267 case PAN_SERIF_TRIANGLE
:
6268 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6271 case PAN_SERIF_NORMAL_SANS
:
6272 case PAN_SERIF_OBTUSE_SANS
:
6273 case PAN_SERIF_PERP_SANS
:
6274 case PAN_SERIF_FLARED
:
6275 case PAN_SERIF_ROUNDED
:
6276 TM
.tmPitchAndFamily
|= FF_SWISS
;
6283 if(FT_IS_SCALABLE(ft_face
))
6284 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6286 if(FT_IS_SFNT(ft_face
))
6288 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6289 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6291 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6294 TM
.tmCharSet
= font
->charset
;
6296 font
->potm
->otmFiller
= 0;
6297 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6298 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6299 font
->potm
->otmfsType
= pOS2
->fsType
;
6300 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6301 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6302 font
->potm
->otmItalicAngle
= 0; /* POST table */
6303 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6304 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6305 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6306 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6307 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6308 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6309 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6310 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6311 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6312 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6313 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6314 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6315 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6316 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6317 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6318 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6319 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6320 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6321 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6322 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6323 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6324 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6325 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6326 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6328 font
->potm
->otmsUnderscoreSize
= 0;
6329 font
->potm
->otmsUnderscorePosition
= 0;
6331 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6332 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6336 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6337 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6338 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6339 strcpyW((WCHAR
*)cp
, family_nameW
);
6341 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6342 strcpyW((WCHAR
*)cp
, style_nameW
);
6344 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6345 strcpyW((WCHAR
*)cp
, family_nameW
);
6346 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6347 strcatW((WCHAR
*)cp
, spaceW
);
6348 strcatW((WCHAR
*)cp
, style_nameW
);
6349 cp
+= lenfam
+ lensty
;
6352 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6353 strcpyW((WCHAR
*)cp
, family_nameW
);
6354 strcatW((WCHAR
*)cp
, spaceW
);
6355 strcatW((WCHAR
*)cp
, style_nameW
);
6359 HeapFree(GetProcessHeap(), 0, style_nameW
);
6360 HeapFree(GetProcessHeap(), 0, family_nameW
);
6364 /*************************************************************
6365 * freetype_GetGlyphOutline
6367 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6368 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6370 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6375 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6376 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6380 EnterCriticalSection( &freetype_cs
);
6381 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6382 LeaveCriticalSection( &freetype_cs
);
6386 /*************************************************************
6387 * freetype_GetTextMetrics
6389 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6391 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6396 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6397 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6401 EnterCriticalSection( &freetype_cs
);
6402 ret
= get_text_metrics( physdev
->font
, metrics
);
6403 LeaveCriticalSection( &freetype_cs
);
6407 /*************************************************************
6408 * freetype_GetOutlineTextMetrics
6410 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6412 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6417 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6418 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6421 TRACE("font=%p\n", physdev
->font
);
6423 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6426 EnterCriticalSection( &freetype_cs
);
6428 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6430 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6432 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6433 scale_outline_font_metrics(physdev
->font
, potm
);
6435 ret
= physdev
->font
->potm
->otmSize
;
6437 LeaveCriticalSection( &freetype_cs
);
6441 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6443 HFONTLIST
*hfontlist
;
6444 child
->font
= alloc_font();
6445 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6446 if(!child
->font
->ft_face
)
6448 free_font(child
->font
);
6453 child
->font
->font_desc
= font
->font_desc
;
6454 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6455 child
->font
->orientation
= font
->orientation
;
6456 child
->font
->scale_y
= font
->scale_y
;
6457 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6458 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6459 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6460 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6461 child
->font
->base_font
= font
;
6462 list_add_head(&child_font_list
, &child
->font
->entry
);
6463 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6467 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6470 CHILD_FONT
*child_font
;
6473 font
= font
->base_font
;
6475 *linked_font
= font
;
6477 if((*glyph
= get_glyph_index(font
, c
)))
6479 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6483 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6485 if(!child_font
->font
)
6486 if(!load_child_font(font
, child_font
))
6489 if(!child_font
->font
->ft_face
)
6491 g
= get_glyph_index(child_font
->font
, c
);
6492 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6496 *linked_font
= child_font
->font
;
6503 /*************************************************************
6504 * freetype_GetCharWidth
6506 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6508 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6511 FT_UInt glyph_index
;
6512 GdiFont
*linked_font
;
6513 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6517 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6518 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6521 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6524 EnterCriticalSection( &freetype_cs
);
6525 for(c
= firstChar
; c
<= lastChar
; c
++) {
6526 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6527 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6528 &gm
, 0, NULL
, &identity
);
6529 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6531 LeaveCriticalSection( &freetype_cs
);
6535 /*************************************************************
6536 * freetype_GetCharABCWidths
6538 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6540 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6543 FT_UInt glyph_index
;
6544 GdiFont
*linked_font
;
6545 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6549 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6550 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6553 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6556 EnterCriticalSection( &freetype_cs
);
6558 for(c
= firstChar
; c
<= lastChar
; c
++) {
6559 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6560 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6561 &gm
, 0, NULL
, &identity
);
6562 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6563 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6564 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6565 FONT_GM(linked_font
,glyph_index
)->bbx
;
6567 LeaveCriticalSection( &freetype_cs
);
6571 /*************************************************************
6572 * freetype_GetCharABCWidthsI
6574 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6576 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6579 FT_UInt glyph_index
;
6580 GdiFont
*linked_font
;
6581 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6585 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6586 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6589 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6593 EnterCriticalSection( &freetype_cs
);
6595 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6597 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6598 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6599 &gm
, 0, NULL
, &identity
);
6600 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6601 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6602 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6603 - FONT_GM(linked_font
,c
)->bbx
;
6606 for(c
= 0; c
< count
; c
++) {
6607 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6608 &gm
, 0, NULL
, &identity
);
6609 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6610 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6611 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6612 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6615 LeaveCriticalSection( &freetype_cs
);
6619 /*************************************************************
6620 * freetype_GetTextExtentExPoint
6622 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6623 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6625 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6630 FT_UInt glyph_index
;
6631 GdiFont
*linked_font
;
6632 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6636 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6637 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6640 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6643 EnterCriticalSection( &freetype_cs
);
6646 get_text_metrics( physdev
->font
, &tm
);
6647 size
->cy
= tm
.tmHeight
;
6649 for(idx
= 0; idx
< count
; idx
++) {
6650 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6651 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6652 &gm
, 0, NULL
, &identity
);
6653 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6655 if (! pnfit
|| ext
<= max_ext
) {
6665 LeaveCriticalSection( &freetype_cs
);
6666 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6670 /*************************************************************
6671 * freetype_GetTextExtentExPointI
6673 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6674 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6676 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6681 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6685 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6686 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6689 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6692 EnterCriticalSection( &freetype_cs
);
6695 get_text_metrics(physdev
->font
, &tm
);
6696 size
->cy
= tm
.tmHeight
;
6698 for(idx
= 0; idx
< count
; idx
++) {
6699 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6700 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6702 if (! pnfit
|| ext
<= max_ext
) {
6712 LeaveCriticalSection( &freetype_cs
);
6713 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6717 /*************************************************************
6718 * freetype_GetFontData
6720 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6722 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6726 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6727 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6730 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6731 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6732 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6734 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6737 /*************************************************************
6738 * freetype_GetTextFace
6740 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6743 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6747 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6748 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6751 n
= strlenW(physdev
->font
->name
) + 1;
6754 lstrcpynW(str
, physdev
->font
->name
, count
);
6760 /*************************************************************
6761 * freetype_GetTextCharsetInfo
6763 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6765 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6769 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6770 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6772 if (fs
) *fs
= physdev
->font
->fs
;
6773 return physdev
->font
->charset
;
6776 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6778 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6779 struct list
*first_hfont
;
6783 EnterCriticalSection( &freetype_cs
);
6784 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6785 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6786 if(font
== linked_font
)
6787 *new_hfont
= dc
->hFont
;
6790 first_hfont
= list_head(&linked_font
->hfontlist
);
6791 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6793 LeaveCriticalSection( &freetype_cs
);
6797 /* Retrieve a list of supported Unicode ranges for a given font.
6798 * Can be called with NULL gs to calculate the buffer size. Returns
6799 * the number of ranges found.
6801 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6803 DWORD num_ranges
= 0;
6805 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6808 FT_ULong char_code
, char_code_prev
;
6811 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6813 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6814 face
->num_glyphs
, glyph_code
, char_code
);
6816 if (!glyph_code
) return 0;
6820 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6821 gs
->ranges
[0].cGlyphs
= 0;
6822 gs
->cGlyphsSupported
= 0;
6828 if (char_code
< char_code_prev
)
6830 ERR("expected increasing char code from FT_Get_Next_Char\n");
6833 if (char_code
- char_code_prev
> 1)
6838 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6839 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6840 gs
->cGlyphsSupported
++;
6845 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6846 gs
->cGlyphsSupported
++;
6848 char_code_prev
= char_code
;
6849 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6853 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6858 /*************************************************************
6859 * freetype_GetFontUnicodeRanges
6861 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6863 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6864 DWORD size
, num_ranges
;
6868 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6869 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6872 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6873 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6876 glyphset
->cbThis
= size
;
6877 glyphset
->cRanges
= num_ranges
;
6878 glyphset
->flAccel
= 0;
6883 /*************************************************************
6884 * freetype_FontIsLinked
6886 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6888 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6893 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6894 return dev
->funcs
->pFontIsLinked( dev
);
6898 EnterCriticalSection( &freetype_cs
);
6899 ret
= !list_empty(&physdev
->font
->child_fonts
);
6900 LeaveCriticalSection( &freetype_cs
);
6904 static BOOL
is_hinting_enabled(void)
6906 /* Use the >= 2.2.0 function if available */
6907 if(pFT_Get_TrueType_Engine_Type
)
6909 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6910 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6912 #ifdef FT_DRIVER_HAS_HINTER
6917 /* otherwise if we've been compiled with < 2.2.0 headers
6918 use the internal macro */
6919 mod
= pFT_Get_Module(library
, "truetype");
6920 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6928 static BOOL
is_subpixel_rendering_enabled( void )
6930 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6931 return pFT_Library_SetLcdFilter
&&
6932 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6938 /*************************************************************************
6939 * GetRasterizerCaps (GDI32.@)
6941 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6943 static int hinting
= -1;
6944 static int subpixel
= -1;
6948 hinting
= is_hinting_enabled();
6949 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6952 if ( subpixel
== -1 )
6954 subpixel
= is_subpixel_rendering_enabled();
6955 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6958 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6959 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6961 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6962 lprs
->nLanguageID
= 0;
6966 /*************************************************************
6967 * freetype_GdiRealizationInfo
6969 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
6971 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6972 realization_info_t
*info
= ptr
;
6976 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
6977 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
6980 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
6983 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
6986 info
->cache_num
= physdev
->font
->cache_num
;
6987 info
->unknown2
= -1;
6991 /*************************************************************************
6992 * Kerning support for TrueType fonts
6994 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6996 struct TT_kern_table
7002 struct TT_kern_subtable
7011 USHORT horizontal
: 1;
7013 USHORT cross_stream
: 1;
7014 USHORT override
: 1;
7015 USHORT reserved1
: 4;
7021 struct TT_format0_kern_subtable
7025 USHORT entrySelector
;
7036 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7037 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7038 const USHORT
*glyph_to_char
,
7039 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7042 const struct TT_kern_pair
*tt_kern_pair
;
7044 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7046 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7048 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7049 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7050 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7052 if (!kern_pair
|| !cPairs
)
7055 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7057 nPairs
= min(nPairs
, cPairs
);
7059 for (i
= 0; i
< nPairs
; i
++)
7061 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7062 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7063 /* this algorithm appears to better match what Windows does */
7064 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7065 if (kern_pair
->iKernAmount
< 0)
7067 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7068 kern_pair
->iKernAmount
-= font
->ppem
;
7070 else if (kern_pair
->iKernAmount
> 0)
7072 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7073 kern_pair
->iKernAmount
+= font
->ppem
;
7075 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7077 TRACE("left %u right %u value %d\n",
7078 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7082 TRACE("copied %u entries\n", nPairs
);
7086 /*************************************************************
7087 * freetype_GetKerningPairs
7089 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7093 const struct TT_kern_table
*tt_kern_table
;
7094 const struct TT_kern_subtable
*tt_kern_subtable
;
7096 USHORT
*glyph_to_char
;
7098 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7100 if (!(font
= physdev
->font
))
7102 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7103 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7107 EnterCriticalSection( &freetype_cs
);
7108 if (font
->total_kern_pairs
!= (DWORD
)-1)
7110 if (cPairs
&& kern_pair
)
7112 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7113 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7115 else cPairs
= font
->total_kern_pairs
;
7117 LeaveCriticalSection( &freetype_cs
);
7121 font
->total_kern_pairs
= 0;
7123 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7125 if (length
== GDI_ERROR
)
7127 TRACE("no kerning data in the font\n");
7128 LeaveCriticalSection( &freetype_cs
);
7132 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7135 WARN("Out of memory\n");
7136 LeaveCriticalSection( &freetype_cs
);
7140 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7142 /* build a glyph index to char code map */
7143 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7146 WARN("Out of memory allocating a glyph index to char code map\n");
7147 HeapFree(GetProcessHeap(), 0, buf
);
7148 LeaveCriticalSection( &freetype_cs
);
7152 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7158 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7160 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7161 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7165 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7167 /* FIXME: This doesn't match what Windows does: it does some fancy
7168 * things with duplicate glyph index to char code mappings, while
7169 * we just avoid overriding existing entries.
7171 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7172 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7174 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7181 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7182 for (n
= 0; n
<= 65535; n
++)
7183 glyph_to_char
[n
] = (USHORT
)n
;
7186 tt_kern_table
= buf
;
7187 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7188 TRACE("version %u, nTables %u\n",
7189 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7191 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7193 for (i
= 0; i
< nTables
; i
++)
7195 struct TT_kern_subtable tt_kern_subtable_copy
;
7197 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7198 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7199 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7201 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7202 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7203 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7205 /* According to the TrueType specification this is the only format
7206 * that will be properly interpreted by Windows and OS/2
7208 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7210 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7212 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7213 glyph_to_char
, NULL
, 0);
7214 font
->total_kern_pairs
+= new_chunk
;
7216 if (!font
->kern_pairs
)
7217 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7218 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7220 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7221 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7223 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7224 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7227 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7229 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7232 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7233 HeapFree(GetProcessHeap(), 0, buf
);
7235 if (cPairs
&& kern_pair
)
7237 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7238 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7240 else cPairs
= font
->total_kern_pairs
;
7242 LeaveCriticalSection( &freetype_cs
);
7246 static const struct gdi_dc_funcs freetype_funcs
=
7248 NULL
, /* pAbortDoc */
7249 NULL
, /* pAbortPath */
7250 NULL
, /* pAlphaBlend */
7251 NULL
, /* pAngleArc */
7254 NULL
, /* pBeginPath */
7255 NULL
, /* pBlendImage */
7256 NULL
, /* pChoosePixelFormat */
7258 NULL
, /* pCloseFigure */
7259 NULL
, /* pCopyBitmap */
7260 NULL
, /* pCreateBitmap */
7261 NULL
, /* pCreateCompatibleDC */
7262 freetype_CreateDC
, /* pCreateDC */
7263 NULL
, /* pDeleteBitmap */
7264 freetype_DeleteDC
, /* pDeleteDC */
7265 NULL
, /* pDeleteObject */
7266 NULL
, /* pDescribePixelFormat */
7267 NULL
, /* pDeviceCapabilities */
7268 NULL
, /* pEllipse */
7270 NULL
, /* pEndPage */
7271 NULL
, /* pEndPath */
7272 freetype_EnumFonts
, /* pEnumFonts */
7273 NULL
, /* pEnumICMProfiles */
7274 NULL
, /* pExcludeClipRect */
7275 NULL
, /* pExtDeviceMode */
7276 NULL
, /* pExtEscape */
7277 NULL
, /* pExtFloodFill */
7278 NULL
, /* pExtSelectClipRgn */
7279 NULL
, /* pExtTextOut */
7280 NULL
, /* pFillPath */
7281 NULL
, /* pFillRgn */
7282 NULL
, /* pFlattenPath */
7283 freetype_FontIsLinked
, /* pFontIsLinked */
7284 NULL
, /* pFrameRgn */
7285 NULL
, /* pGdiComment */
7286 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7287 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7288 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7289 freetype_GetCharWidth
, /* pGetCharWidth */
7290 NULL
, /* pGetDeviceCaps */
7291 NULL
, /* pGetDeviceGammaRamp */
7292 freetype_GetFontData
, /* pGetFontData */
7293 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7294 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7295 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7296 NULL
, /* pGetICMProfile */
7297 NULL
, /* pGetImage */
7298 freetype_GetKerningPairs
, /* pGetKerningPairs */
7299 NULL
, /* pGetNearestColor */
7300 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7301 NULL
, /* pGetPixel */
7302 NULL
, /* pGetPixelFormat */
7303 NULL
, /* pGetSystemPaletteEntries */
7304 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7305 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7306 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7307 freetype_GetTextFace
, /* pGetTextFace */
7308 freetype_GetTextMetrics
, /* pGetTextMetrics */
7309 NULL
, /* pGradientFill */
7310 NULL
, /* pIntersectClipRect */
7311 NULL
, /* pInvertRgn */
7313 NULL
, /* pModifyWorldTransform */
7315 NULL
, /* pOffsetClipRgn */
7316 NULL
, /* pOffsetViewportOrg */
7317 NULL
, /* pOffsetWindowOrg */
7318 NULL
, /* pPaintRgn */
7321 NULL
, /* pPolyBezier */
7322 NULL
, /* pPolyBezierTo */
7323 NULL
, /* pPolyDraw */
7324 NULL
, /* pPolyPolygon */
7325 NULL
, /* pPolyPolyline */
7326 NULL
, /* pPolygon */
7327 NULL
, /* pPolyline */
7328 NULL
, /* pPolylineTo */
7329 NULL
, /* pPutImage */
7330 NULL
, /* pRealizeDefaultPalette */
7331 NULL
, /* pRealizePalette */
7332 NULL
, /* pRectangle */
7333 NULL
, /* pResetDC */
7334 NULL
, /* pRestoreDC */
7335 NULL
, /* pRoundRect */
7337 NULL
, /* pScaleViewportExt */
7338 NULL
, /* pScaleWindowExt */
7339 NULL
, /* pSelectBitmap */
7340 NULL
, /* pSelectBrush */
7341 NULL
, /* pSelectClipPath */
7342 freetype_SelectFont
, /* pSelectFont */
7343 NULL
, /* pSelectPalette */
7344 NULL
, /* pSelectPen */
7345 NULL
, /* pSetArcDirection */
7346 NULL
, /* pSetBkColor */
7347 NULL
, /* pSetBkMode */
7348 NULL
, /* pSetDCBrushColor */
7349 NULL
, /* pSetDCPenColor */
7350 NULL
, /* pSetDIBColorTable */
7351 NULL
, /* pSetDIBitsToDevice */
7352 NULL
, /* pSetDeviceClipping */
7353 NULL
, /* pSetDeviceGammaRamp */
7354 NULL
, /* pSetLayout */
7355 NULL
, /* pSetMapMode */
7356 NULL
, /* pSetMapperFlags */
7357 NULL
, /* pSetPixel */
7358 NULL
, /* pSetPixelFormat */
7359 NULL
, /* pSetPolyFillMode */
7360 NULL
, /* pSetROP2 */
7361 NULL
, /* pSetRelAbs */
7362 NULL
, /* pSetStretchBltMode */
7363 NULL
, /* pSetTextAlign */
7364 NULL
, /* pSetTextCharacterExtra */
7365 NULL
, /* pSetTextColor */
7366 NULL
, /* pSetTextJustification */
7367 NULL
, /* pSetViewportExt */
7368 NULL
, /* pSetViewportOrg */
7369 NULL
, /* pSetWindowExt */
7370 NULL
, /* pSetWindowOrg */
7371 NULL
, /* pSetWorldTransform */
7372 NULL
, /* pStartDoc */
7373 NULL
, /* pStartPage */
7374 NULL
, /* pStretchBlt */
7375 NULL
, /* pStretchDIBits */
7376 NULL
, /* pStrokeAndFillPath */
7377 NULL
, /* pStrokePath */
7378 NULL
, /* pSwapBuffers */
7379 NULL
, /* pUnrealizePalette */
7380 NULL
, /* pWidenPath */
7381 /* OpenGL not supported */
7384 #else /* HAVE_FREETYPE */
7386 /*************************************************************************/
7388 BOOL
WineEngInit(void)
7392 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7397 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7399 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7403 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7405 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7409 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7411 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7415 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7420 /*************************************************************************
7421 * GetRasterizerCaps (GDI32.@)
7423 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7425 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7427 lprs
->nLanguageID
= 0;
7431 #endif /* HAVE_FREETYPE */