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 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1526 WCHAR
*name
, *english_name
;
1528 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1530 family
= find_family_from_name( name
);
1534 family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1535 family
->FamilyName
= strdupW( name
);
1536 family
->EnglishName
= english_name
? strdupW( english_name
) : NULL
;
1537 list_init( &family
->faces
);
1538 family
->replacement
= &family
->faces
;
1539 list_add_tail( &font_list
, &family
->entry
);
1543 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1544 subst
->from
.name
= strdupW( english_name
);
1545 subst
->from
.charset
= -1;
1546 subst
->to
.name
= strdupW( name
);
1547 subst
->to
.charset
= -1;
1548 add_font_subst( &font_subst_list
, subst
, 0 );
1551 HeapFree( GetProcessHeap(), 0, name
);
1552 HeapFree( GetProcessHeap(), 0, english_name
);
1558 #define ADDFONT_EXTERNAL_FONT 0x01
1559 #define ADDFONT_FORCE_BITMAP 0x02
1560 #define ADDFONT_ADD_TO_CACHE 0x04
1562 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
)
1572 struct list
*face_elem_ptr
;
1573 FT_WinFNT_HeaderRec winfnt_header
;
1574 int internal_leading
;
1576 My_FT_Bitmap_Size
*size
= NULL
;
1579 if(!FT_IS_SCALABLE(ft_face
))
1580 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1582 family
= get_family( ft_face
, vertical
);
1584 StyleW
= towstr(CP_ACP
, ft_face
->style_name
);
1586 internal_leading
= 0;
1587 memset(&fs
, 0, sizeof(fs
));
1589 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1591 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1592 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1593 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1594 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1595 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1596 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1597 if(pOS2
->version
== 0) {
1600 if(pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1601 fs
.fsCsb
[0] |= FS_LATIN1
;
1603 fs
.fsCsb
[0] |= FS_SYMBOL
;
1606 else if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1608 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1609 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1610 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1612 internal_leading
= winfnt_header
.internal_leading
;
1615 pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
);
1616 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1617 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1618 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1619 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1620 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1621 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1622 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1624 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1625 TRACE("Original font is newer so skipping this one\n");
1626 HeapFree(GetProcessHeap(), 0, StyleW
);
1629 TRACE("Replacing original with this one\n");
1630 list_remove(&face
->entry
);
1631 HeapFree(GetProcessHeap(), 0, face
->file
);
1632 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1633 HeapFree(GetProcessHeap(), 0, face
->FullName
);
1634 HeapFree(GetProcessHeap(), 0, face
);
1639 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1640 face
->cached_enum_data
= NULL
;
1641 face
->StyleName
= StyleW
;
1642 face
->FullName
= get_face_name(ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1645 face
->file
= strdupA(file
);
1646 face
->font_data_ptr
= NULL
;
1647 face
->font_data_size
= 0;
1652 face
->font_data_ptr
= font_data_ptr
;
1653 face
->font_data_size
= font_data_size
;
1655 face
->face_index
= face_index
;
1657 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1658 face
->ntmFlags
|= NTM_ITALIC
;
1659 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1660 face
->ntmFlags
|= NTM_BOLD
;
1661 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1662 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1663 face
->family
= family
;
1664 face
->vertical
= vertical
;
1665 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1668 if(FT_IS_SCALABLE(ft_face
)) {
1669 memset(&face
->size
, 0, sizeof(face
->size
));
1670 face
->scalable
= TRUE
;
1672 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1673 size
->height
, size
->width
, size
->size
>> 6,
1674 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1675 face
->size
.height
= size
->height
;
1676 face
->size
.width
= size
->width
;
1677 face
->size
.size
= size
->size
;
1678 face
->size
.x_ppem
= size
->x_ppem
;
1679 face
->size
.y_ppem
= size
->y_ppem
;
1680 face
->size
.internal_leading
= internal_leading
;
1681 face
->scalable
= FALSE
;
1684 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1686 if (!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1688 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1689 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1692 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1693 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1694 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1695 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1697 if(face
->fs
.fsCsb
[0] == 0)
1701 /* let's see if we can find any interesting cmaps */
1702 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1703 switch(ft_face
->charmaps
[i
]->encoding
) {
1704 case FT_ENCODING_UNICODE
:
1705 case FT_ENCODING_APPLE_ROMAN
:
1706 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1708 case FT_ENCODING_MS_SYMBOL
:
1709 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1717 if(flags
& ADDFONT_ADD_TO_CACHE
)
1718 add_face_to_cache(face
);
1720 AddFaceToFamily(face
, family
);
1722 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1724 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1725 debugstr_w(StyleW
));
1728 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1733 FT_Long face_index
= 0, num_faces
;
1736 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1737 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1739 #ifdef HAVE_CARBON_CARBON_H
1742 char **mac_list
= expand_mac_font(file
);
1745 BOOL had_one
= FALSE
;
1747 for(cursor
= mac_list
; *cursor
; cursor
++)
1750 AddFontToList(*cursor
, NULL
, 0, flags
);
1751 HeapFree(GetProcessHeap(), 0, *cursor
);
1753 HeapFree(GetProcessHeap(), 0, mac_list
);
1758 #endif /* HAVE_CARBON_CARBON_H */
1763 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1764 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1767 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1768 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1772 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1776 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*/
1777 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1778 pFT_Done_Face(ft_face
);
1782 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1783 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1784 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1785 pFT_Done_Face(ft_face
);
1789 if(FT_IS_SFNT(ft_face
))
1791 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1792 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1793 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
))
1795 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1796 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1797 pFT_Done_Face(ft_face
);
1801 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1802 we don't want to load these. */
1803 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1807 if(!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1809 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1810 pFT_Done_Face(ft_face
);
1816 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1817 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1818 pFT_Done_Face(ft_face
);
1822 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1824 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1825 pFT_Done_Face(ft_face
);
1829 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1832 if (FT_HAS_VERTICAL(ft_face
))
1834 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1838 num_faces
= ft_face
->num_faces
;
1839 pFT_Done_Face(ft_face
);
1840 } while(num_faces
> ++face_index
);
1844 static void DumpFontList(void)
1848 struct list
*family_elem_ptr
, *face_elem_ptr
;
1850 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1851 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1852 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1853 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1854 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1855 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1857 TRACE(" %d", face
->size
.height
);
1864 /***********************************************************
1865 * The replacement list is a way to map an entire font
1866 * family onto another family. For example adding
1868 * [HKCU\Software\Wine\Fonts\Replacements]
1869 * "Wingdings"="Winedings"
1871 * would enumerate the Winedings font both as Winedings and
1872 * Wingdings. However if a real Wingdings font is present the
1873 * replacement does not take place.
1876 static void LoadReplaceList(void)
1879 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1884 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1885 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1887 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1888 &valuelen
, &datalen
, NULL
, NULL
);
1890 valuelen
++; /* returned value doesn't include room for '\0' */
1891 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1892 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1896 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1897 &dlen
) == ERROR_SUCCESS
) {
1898 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1899 /* "NewName"="Oldname" */
1900 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1902 if(!find_family_from_any_name(value
))
1904 Family
* const family
= find_family_from_any_name(data
);
1907 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
1908 if (new_family
!= NULL
)
1910 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
1911 new_family
->FamilyName
= strdupW(value
);
1912 new_family
->EnglishName
= NULL
;
1913 list_init(&new_family
->faces
);
1914 new_family
->replacement
= &family
->faces
;
1915 list_add_tail(&font_list
, &new_family
->entry
);
1920 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
1925 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
1927 /* reset dlen and vlen */
1931 HeapFree(GetProcessHeap(), 0, data
);
1932 HeapFree(GetProcessHeap(), 0, value
);
1937 static const WCHAR
*font_links_list
[] =
1939 Lucida_Sans_Unicode
,
1940 Microsoft_Sans_Serif
,
1944 static const struct font_links_defaults_list
1946 /* Keyed off substitution for "MS Shell Dlg" */
1947 const WCHAR
*shelldlg
;
1948 /* Maximum of four substitutes, plus terminating NULL pointer */
1949 const WCHAR
*substitutes
[5];
1950 } font_links_defaults_list
[] =
1952 /* Non East-Asian */
1953 { Tahoma
, /* FIXME unverified ordering */
1954 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
1956 /* Below lists are courtesy of
1957 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1961 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
1963 /* Chinese Simplified */
1965 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
1969 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
1971 /* Chinese Traditional */
1973 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
1978 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
1980 SYSTEM_LINKS
*font_link
;
1982 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1984 if(!strcmpiW(font_link
->font_name
, name
))
1991 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2003 SYSTEM_LINKS
*font_link
;
2005 psub
= get_font_subst(&font_subst_list
, name
, -1);
2006 /* Don't store fonts that are only substitutes for other fonts */
2009 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2013 font_link
= find_font_link(name
);
2014 if (font_link
== NULL
)
2016 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2017 font_link
->font_name
= strdupW(name
);
2018 list_init(&font_link
->links
);
2019 list_add_tail(&system_links
, &font_link
->entry
);
2022 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2023 for (i
= 0; values
[i
] != NULL
; i
++)
2025 const struct list
*face_list
;
2026 CHILD_FONT
*child_font
;
2029 if (!strcmpiW(name
,value
))
2031 psub
= get_font_subst(&font_subst_list
, value
, -1);
2033 value
= psub
->to
.name
;
2034 family
= find_family_from_name(value
);
2038 /* Use first extant filename for this Family */
2039 face_list
= get_face_list_from_family(family
);
2040 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2044 file
= strrchr(face
->file
, '/');
2053 fileW
= towstr(CP_UNIXCP
, file
);
2055 face
= find_face_from_filename(fileW
, value
);
2058 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2062 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2063 child_font
->face
= face
;
2064 child_font
->font
= NULL
;
2065 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2066 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2067 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2068 list_add_tail(&font_link
->links
, &child_font
->entry
);
2070 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2071 HeapFree(GetProcessHeap(), 0, fileW
);
2077 /*************************************************************
2080 static BOOL
init_system_links(void)
2084 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2085 WCHAR
*value
, *data
;
2086 WCHAR
*entry
, *next
;
2087 SYSTEM_LINKS
*font_link
, *system_font_link
;
2088 CHILD_FONT
*child_font
;
2089 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2090 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2091 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2096 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2098 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2099 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2100 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2101 val_len
= max_val
+ 1;
2102 data_len
= max_data
;
2104 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2106 psub
= get_font_subst(&font_subst_list
, value
, -1);
2107 /* Don't store fonts that are only substitutes for other fonts */
2110 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2113 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2114 font_link
->font_name
= strdupW(value
);
2115 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2116 list_init(&font_link
->links
);
2117 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2120 CHILD_FONT
*child_font
;
2122 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2124 next
= entry
+ strlenW(entry
) + 1;
2126 face_name
= strchrW(entry
, ',');
2130 while(isspaceW(*face_name
))
2133 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2135 face_name
= psub
->to
.name
;
2137 face
= find_face_from_filename(entry
, face_name
);
2140 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2144 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2145 child_font
->face
= face
;
2146 child_font
->font
= NULL
;
2147 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2148 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2149 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2150 list_add_tail(&font_link
->links
, &child_font
->entry
);
2152 list_add_tail(&system_links
, &font_link
->entry
);
2154 val_len
= max_val
+ 1;
2155 data_len
= max_data
;
2158 HeapFree(GetProcessHeap(), 0, value
);
2159 HeapFree(GetProcessHeap(), 0, data
);
2164 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2166 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2170 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2172 const FontSubst
*psub2
;
2173 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2175 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2177 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2178 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2180 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2181 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2183 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2185 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2191 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2194 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2195 system_font_link
->font_name
= strdupW(System
);
2196 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2197 list_init(&system_font_link
->links
);
2199 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2202 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2203 child_font
->face
= face
;
2204 child_font
->font
= NULL
;
2205 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2206 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2207 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2208 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2210 font_link
= find_font_link(Tahoma
);
2211 if (font_link
!= NULL
)
2213 CHILD_FONT
*font_link_entry
;
2214 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2216 CHILD_FONT
*new_child
;
2217 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2218 new_child
->face
= font_link_entry
->face
;
2219 new_child
->font
= NULL
;
2220 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2221 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2222 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2225 list_add_tail(&system_links
, &system_font_link
->entry
);
2229 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2232 struct dirent
*dent
;
2233 char path
[MAX_PATH
];
2235 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2237 dir
= opendir(dirname
);
2239 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2242 while((dent
= readdir(dir
)) != NULL
) {
2243 struct stat statbuf
;
2245 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2248 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2250 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2252 if(stat(path
, &statbuf
) == -1)
2254 WARN("Can't stat %s\n", debugstr_a(path
));
2257 if(S_ISDIR(statbuf
.st_mode
))
2258 ReadFontDir(path
, external_fonts
);
2261 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2262 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2263 AddFontToList(path
, NULL
, 0, addfont_flags
);
2270 static void load_fontconfig_fonts(void)
2272 #ifdef SONAME_LIBFONTCONFIG
2273 void *fc_handle
= NULL
;
2282 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2284 TRACE("Wine cannot find the fontconfig library (%s).\n",
2285 SONAME_LIBFONTCONFIG
);
2288 #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;}
2289 LOAD_FUNCPTR(FcConfigGetCurrent
);
2290 LOAD_FUNCPTR(FcFontList
);
2291 LOAD_FUNCPTR(FcFontSetDestroy
);
2292 LOAD_FUNCPTR(FcInit
);
2293 LOAD_FUNCPTR(FcObjectSetAdd
);
2294 LOAD_FUNCPTR(FcObjectSetCreate
);
2295 LOAD_FUNCPTR(FcObjectSetDestroy
);
2296 LOAD_FUNCPTR(FcPatternCreate
);
2297 LOAD_FUNCPTR(FcPatternDestroy
);
2298 LOAD_FUNCPTR(FcPatternGetBool
);
2299 LOAD_FUNCPTR(FcPatternGetString
);
2302 if(!pFcInit()) return;
2304 config
= pFcConfigGetCurrent();
2305 pat
= pFcPatternCreate();
2306 os
= pFcObjectSetCreate();
2307 pFcObjectSetAdd(os
, FC_FILE
);
2308 pFcObjectSetAdd(os
, FC_SCALABLE
);
2309 fontset
= pFcFontList(config
, pat
, os
);
2310 if(!fontset
) return;
2311 for(i
= 0; i
< fontset
->nfont
; i
++) {
2314 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2316 TRACE("fontconfig: %s\n", file
);
2318 /* We're just interested in OT/TT fonts for now, so this hack just
2319 picks up the scalable fonts without extensions .pf[ab] to save time
2320 loading every other font */
2322 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2324 TRACE("not scalable\n");
2328 len
= strlen( file
);
2329 if(len
< 4) continue;
2330 ext
= &file
[ len
- 3 ];
2331 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2332 AddFontToList(file
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2334 pFcFontSetDestroy(fontset
);
2335 pFcObjectSetDestroy(os
);
2336 pFcPatternDestroy(pat
);
2342 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2345 const char *data_dir
= wine_get_data_dir();
2347 if (!data_dir
) data_dir
= wine_get_build_dir();
2354 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2356 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2358 strcpy(unix_name
, data_dir
);
2359 strcat(unix_name
, "/fonts/");
2361 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2363 EnterCriticalSection( &freetype_cs
);
2364 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2365 LeaveCriticalSection( &freetype_cs
);
2366 HeapFree(GetProcessHeap(), 0, unix_name
);
2371 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2373 static const WCHAR slashW
[] = {'\\','\0'};
2375 WCHAR windowsdir
[MAX_PATH
];
2378 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2379 strcatW(windowsdir
, fontsW
);
2380 strcatW(windowsdir
, slashW
);
2381 strcatW(windowsdir
, file
);
2382 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2383 EnterCriticalSection( &freetype_cs
);
2384 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2385 LeaveCriticalSection( &freetype_cs
);
2386 HeapFree(GetProcessHeap(), 0, unixname
);
2391 static void load_system_fonts(void)
2394 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2395 const WCHAR
* const *value
;
2397 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2400 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2401 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2402 strcatW(windowsdir
, fontsW
);
2403 for(value
= SystemFontValues
; *value
; value
++) {
2404 dlen
= sizeof(data
);
2405 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2409 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2410 if((unixname
= wine_get_unix_file_name(pathW
))) {
2411 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2412 HeapFree(GetProcessHeap(), 0, unixname
);
2415 load_font_from_data_dir(data
);
2422 /*************************************************************
2424 * This adds registry entries for any externally loaded fonts
2425 * (fonts from fontconfig or FontDirs). It also deletes entries
2426 * of no longer existing fonts.
2429 static void update_reg_entries(void)
2431 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2436 struct list
*family_elem_ptr
, *face_elem_ptr
;
2438 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2439 static const WCHAR spaceW
[] = {' ', '\0'};
2442 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2443 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2444 ERR("Can't create Windows font reg key\n");
2448 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2449 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2450 ERR("Can't create Windows font reg key\n");
2454 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2455 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2456 ERR("Can't create external font reg key\n");
2460 /* enumerate the fonts and add external ones to the two keys */
2462 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2463 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2464 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2465 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2466 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2467 if(!face
->external
) continue;
2469 if (!(face
->ntmFlags
& NTM_REGULAR
))
2470 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2471 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2472 strcpyW(valueW
, family
->FamilyName
);
2473 if(len
!= len_fam
) {
2474 strcatW(valueW
, spaceW
);
2475 strcatW(valueW
, face
->StyleName
);
2477 strcatW(valueW
, TrueType
);
2479 file
= wine_get_dos_file_name(face
->file
);
2481 len
= strlenW(file
) + 1;
2484 if((path
= strrchr(face
->file
, '/')) == NULL
)
2488 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2490 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2491 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2493 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2494 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2495 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2497 HeapFree(GetProcessHeap(), 0, file
);
2498 HeapFree(GetProcessHeap(), 0, valueW
);
2502 if(external_key
) RegCloseKey(external_key
);
2503 if(win9x_key
) RegCloseKey(win9x_key
);
2504 if(winnt_key
) RegCloseKey(winnt_key
);
2508 static void delete_external_font_keys(void)
2510 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2511 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2515 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2516 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2517 ERR("Can't create Windows font reg key\n");
2521 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2522 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2523 ERR("Can't create Windows font reg key\n");
2527 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2528 ERR("Can't create external font reg key\n");
2532 /* Delete all external fonts added last time */
2534 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2535 &valuelen
, &datalen
, NULL
, NULL
);
2536 valuelen
++; /* returned value doesn't include room for '\0' */
2537 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2538 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2540 dlen
= datalen
* sizeof(WCHAR
);
2543 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2544 &dlen
) == ERROR_SUCCESS
) {
2546 RegDeleteValueW(winnt_key
, valueW
);
2547 RegDeleteValueW(win9x_key
, valueW
);
2548 /* reset dlen and vlen */
2552 HeapFree(GetProcessHeap(), 0, data
);
2553 HeapFree(GetProcessHeap(), 0, valueW
);
2555 /* Delete the old external fonts key */
2556 RegCloseKey(external_key
);
2557 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2560 if(win9x_key
) RegCloseKey(win9x_key
);
2561 if(winnt_key
) RegCloseKey(winnt_key
);
2564 /*************************************************************
2565 * WineEngAddFontResourceEx
2568 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2574 if (ft_handle
) /* do it only if we have freetype up and running */
2579 FIXME("Ignoring flags %x\n", flags
);
2581 if((unixname
= wine_get_unix_file_name(file
)))
2583 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2585 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2586 EnterCriticalSection( &freetype_cs
);
2587 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2588 LeaveCriticalSection( &freetype_cs
);
2589 HeapFree(GetProcessHeap(), 0, unixname
);
2591 if (!ret
&& !strchrW(file
, '\\')) {
2592 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2593 ret
= load_font_from_winfonts_dir(file
);
2595 /* Try in datadir/fonts (or builddir/fonts),
2596 * needed for Magic the Gathering Online
2598 ret
= load_font_from_data_dir(file
);
2605 /*************************************************************
2606 * WineEngAddFontMemResourceEx
2609 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2613 if (ft_handle
) /* do it only if we have freetype up and running */
2615 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2617 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2618 memcpy(pFontCopy
, pbFont
, cbFont
);
2620 EnterCriticalSection( &freetype_cs
);
2621 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2622 LeaveCriticalSection( &freetype_cs
);
2626 TRACE("AddFontToList failed\n");
2627 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2630 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2631 * For now return something unique but quite random
2633 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2634 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2641 /*************************************************************
2642 * WineEngRemoveFontResourceEx
2645 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2648 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2652 static const struct nls_update_font_list
2654 UINT ansi_cp
, oem_cp
;
2655 const char *oem
, *fixed
, *system
;
2656 const char *courier
, *serif
, *small
, *sserif
;
2657 /* these are for font substitutes */
2658 const char *shelldlg
, *tmsrmn
;
2659 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2663 const char *from
, *to
;
2664 } arial_0
, courier_new_0
, times_new_roman_0
;
2665 } nls_update_font_list
[] =
2667 /* Latin 1 (United States) */
2668 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2669 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2670 "Tahoma","Times New Roman",
2671 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2674 /* Latin 1 (Multilingual) */
2675 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2676 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2677 "Tahoma","Times New Roman", /* FIXME unverified */
2678 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2681 /* Eastern Europe */
2682 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2683 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2684 "Tahoma","Times New Roman", /* FIXME unverified */
2685 "Fixedsys,238", "System,238",
2686 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2687 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2688 { "Arial CE,0", "Arial,238" },
2689 { "Courier New CE,0", "Courier New,238" },
2690 { "Times New Roman CE,0", "Times New Roman,238" }
2693 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2694 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2695 "Tahoma","Times New Roman", /* FIXME unverified */
2696 "Fixedsys,204", "System,204",
2697 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2698 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2699 { "Arial Cyr,0", "Arial,204" },
2700 { "Courier New Cyr,0", "Courier New,204" },
2701 { "Times New Roman Cyr,0", "Times New Roman,204" }
2704 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2705 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2706 "Tahoma","Times New Roman", /* FIXME unverified */
2707 "Fixedsys,161", "System,161",
2708 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2709 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2710 { "Arial Greek,0", "Arial,161" },
2711 { "Courier New Greek,0", "Courier New,161" },
2712 { "Times New Roman Greek,0", "Times New Roman,161" }
2715 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2716 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2717 "Tahoma","Times New Roman", /* FIXME unverified */
2718 "Fixedsys,162", "System,162",
2719 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2720 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2721 { "Arial Tur,0", "Arial,162" },
2722 { "Courier New Tur,0", "Courier New,162" },
2723 { "Times New Roman Tur,0", "Times New Roman,162" }
2726 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2727 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2728 "Tahoma","Times New Roman", /* FIXME unverified */
2729 "Fixedsys,177", "System,177",
2730 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2731 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2735 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2736 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2737 "Tahoma","Times New Roman", /* FIXME unverified */
2738 "Fixedsys,178", "System,178",
2739 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2740 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2744 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2745 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2746 "Tahoma","Times New Roman", /* FIXME unverified */
2747 "Fixedsys,186", "System,186",
2748 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2749 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2750 { "Arial Baltic,0", "Arial,186" },
2751 { "Courier New Baltic,0", "Courier New,186" },
2752 { "Times New Roman Baltic,0", "Times New Roman,186" }
2755 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2756 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2757 "Tahoma","Times New Roman", /* FIXME unverified */
2758 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2762 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2763 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2764 "Tahoma","Times New Roman", /* FIXME unverified */
2765 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2769 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2770 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2771 "MS UI Gothic","MS Serif",
2772 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2775 /* Chinese Simplified */
2776 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2777 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2778 "SimSun", "NSimSun",
2779 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2783 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2784 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2786 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2789 /* Chinese Traditional */
2790 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2791 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2792 "PMingLiU", "MingLiU",
2793 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2798 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2800 return ( ansi_cp
== 932 /* CP932 for Japanese */
2801 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2802 || ansi_cp
== 949 /* CP949 for Korean */
2803 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2806 static inline HKEY
create_fonts_NT_registry_key(void)
2810 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2811 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2815 static inline HKEY
create_fonts_9x_registry_key(void)
2819 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2820 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2824 static inline HKEY
create_config_fonts_registry_key(void)
2828 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2829 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2833 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2835 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2836 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2837 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2838 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2841 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2844 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2846 RegDeleteValueA(hkey
, name
);
2849 static void update_font_info(void)
2851 char buf
[40], cpbuf
[40];
2854 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2857 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2860 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2861 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2862 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2863 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2864 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2866 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2867 if (is_dbcs_ansi_cp(ansi_cp
))
2868 use_default_fallback
= TRUE
;
2871 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2873 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2878 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2880 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2882 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2885 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2889 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2890 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2892 hkey
= create_config_fonts_registry_key();
2893 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2894 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2895 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2898 hkey
= create_fonts_NT_registry_key();
2899 add_font_list(hkey
, &nls_update_font_list
[i
]);
2902 hkey
= create_fonts_9x_registry_key();
2903 add_font_list(hkey
, &nls_update_font_list
[i
]);
2906 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2908 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2909 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2910 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2911 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2913 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2914 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2915 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2916 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2917 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2918 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2919 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2920 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2922 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2923 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2924 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2932 /* Delete the FontSubstitutes from other locales */
2933 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2935 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2936 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2937 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2943 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2946 static BOOL
init_freetype(void)
2948 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2951 "Wine cannot find the FreeType font library. To enable Wine to\n"
2952 "use TrueType fonts please install a version of FreeType greater than\n"
2953 "or equal to 2.0.5.\n"
2954 "http://www.freetype.org\n");
2958 #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;}
2960 LOAD_FUNCPTR(FT_Done_Face
)
2961 LOAD_FUNCPTR(FT_Get_Char_Index
)
2962 LOAD_FUNCPTR(FT_Get_First_Char
)
2963 LOAD_FUNCPTR(FT_Get_Module
)
2964 LOAD_FUNCPTR(FT_Get_Next_Char
)
2965 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2966 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2967 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2968 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
2969 LOAD_FUNCPTR(FT_Init_FreeType
)
2970 LOAD_FUNCPTR(FT_Library_Version
)
2971 LOAD_FUNCPTR(FT_Load_Glyph
)
2972 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
2973 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2974 #ifndef FT_MULFIX_INLINED
2975 LOAD_FUNCPTR(FT_MulFix
)
2977 LOAD_FUNCPTR(FT_New_Face
)
2978 LOAD_FUNCPTR(FT_New_Memory_Face
)
2979 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2980 LOAD_FUNCPTR(FT_Outline_Transform
)
2981 LOAD_FUNCPTR(FT_Outline_Translate
)
2982 LOAD_FUNCPTR(FT_Render_Glyph
)
2983 LOAD_FUNCPTR(FT_Select_Charmap
)
2984 LOAD_FUNCPTR(FT_Set_Charmap
)
2985 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2986 LOAD_FUNCPTR(FT_Vector_Transform
)
2987 LOAD_FUNCPTR(FT_Vector_Unit
)
2989 /* Don't warn if these ones are missing */
2990 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2991 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2992 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
2995 if(pFT_Init_FreeType(&library
) != 0) {
2996 ERR("Can't init FreeType library\n");
2997 wine_dlclose(ft_handle
, NULL
, 0);
3001 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3003 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3004 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3005 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3006 ((FT_Version
.patch
) & 0x0000ff);
3008 font_driver
= &freetype_funcs
;
3013 "Wine cannot find certain functions that it needs inside the FreeType\n"
3014 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3015 "FreeType to at least version 2.1.4.\n"
3016 "http://www.freetype.org\n");
3017 wine_dlclose(ft_handle
, NULL
, 0);
3022 static void init_font_list(void)
3024 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3025 static const WCHAR pathW
[] = {'P','a','t','h',0};
3027 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3028 WCHAR windowsdir
[MAX_PATH
];
3031 const char *data_dir
;
3033 delete_external_font_keys();
3035 /* load the system bitmap fonts */
3036 load_system_fonts();
3038 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3039 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3040 strcatW(windowsdir
, fontsW
);
3041 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3043 ReadFontDir(unixname
, FALSE
);
3044 HeapFree(GetProcessHeap(), 0, unixname
);
3047 /* load the system truetype fonts */
3048 data_dir
= wine_get_data_dir();
3049 if (!data_dir
) data_dir
= wine_get_build_dir();
3050 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3052 strcpy(unixname
, data_dir
);
3053 strcat(unixname
, "/fonts/");
3054 ReadFontDir(unixname
, TRUE
);
3055 HeapFree(GetProcessHeap(), 0, unixname
);
3058 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3059 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3060 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3062 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3063 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3064 &hkey
) == ERROR_SUCCESS
)
3066 LPWSTR data
, valueW
;
3067 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3068 &valuelen
, &datalen
, NULL
, NULL
);
3070 valuelen
++; /* returned value doesn't include room for '\0' */
3071 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3072 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3075 dlen
= datalen
* sizeof(WCHAR
);
3077 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3078 &dlen
) == ERROR_SUCCESS
)
3080 if(data
[0] && (data
[1] == ':'))
3082 if((unixname
= wine_get_unix_file_name(data
)))
3084 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3085 HeapFree(GetProcessHeap(), 0, unixname
);
3088 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3090 WCHAR pathW
[MAX_PATH
];
3091 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3094 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3095 if((unixname
= wine_get_unix_file_name(pathW
)))
3097 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3098 HeapFree(GetProcessHeap(), 0, unixname
);
3101 load_font_from_data_dir(data
);
3103 /* reset dlen and vlen */
3108 HeapFree(GetProcessHeap(), 0, data
);
3109 HeapFree(GetProcessHeap(), 0, valueW
);
3113 load_fontconfig_fonts();
3115 /* then look in any directories that we've specified in the config file */
3116 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3117 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3123 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3125 len
+= sizeof(WCHAR
);
3126 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3127 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3129 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3130 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3131 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3132 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3136 LPSTR next
= strchr( ptr
, ':' );
3137 if (next
) *next
++ = 0;
3138 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3139 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3141 strcpy( unixname
, home
);
3142 strcat( unixname
, ptr
+ 1 );
3143 ReadFontDir( unixname
, TRUE
);
3144 HeapFree( GetProcessHeap(), 0, unixname
);
3147 ReadFontDir( ptr
, TRUE
);
3150 HeapFree( GetProcessHeap(), 0, valueA
);
3152 HeapFree( GetProcessHeap(), 0, valueW
);
3158 /* Mac default font locations. */
3159 ReadFontDir( "/Library/Fonts", TRUE
);
3160 ReadFontDir( "/Network/Library/Fonts", TRUE
);
3161 ReadFontDir( "/System/Library/Fonts", TRUE
);
3162 if ((home
= getenv( "HOME" )))
3164 unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(home
)+15 );
3165 strcpy( unixname
, home
);
3166 strcat( unixname
, "/Library/Fonts" );
3167 ReadFontDir( unixname
, TRUE
);
3168 HeapFree( GetProcessHeap(), 0, unixname
);
3173 static BOOL
move_to_front(const WCHAR
*name
)
3175 Family
*family
, *cursor2
;
3176 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3178 if(!strcmpiW(family
->FamilyName
, name
))
3180 list_remove(&family
->entry
);
3181 list_add_head(&font_list
, &family
->entry
);
3188 static BOOL
set_default(const WCHAR
**name_list
)
3192 if (move_to_front(*name_list
)) return TRUE
;
3199 static void reorder_font_list(void)
3201 set_default( default_serif_list
);
3202 set_default( default_fixed_list
);
3203 set_default( default_sans_list
);
3206 /*************************************************************
3209 * Initialize FreeType library and create a list of available faces
3211 BOOL
WineEngInit(void)
3213 HKEY hkey_font_cache
;
3217 /* update locale dependent font info in registry */
3220 if(!init_freetype()) return FALSE
;
3222 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3224 ERR("Failed to create font mutex\n");
3227 WaitForSingleObject(font_mutex
, INFINITE
);
3229 create_font_cache_key(&hkey_font_cache
, &disposition
);
3231 if(disposition
== REG_CREATED_NEW_KEY
)
3234 load_font_list_from_cache(hkey_font_cache
);
3236 RegCloseKey(hkey_font_cache
);
3238 reorder_font_list();
3245 if(disposition
== REG_CREATED_NEW_KEY
)
3246 update_reg_entries();
3248 init_system_links();
3250 ReleaseMutex(font_mutex
);
3255 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3258 TT_HoriHeader
*pHori
;
3262 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3263 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3265 if(height
== 0) height
= 16;
3267 /* Calc. height of EM square:
3269 * For +ve lfHeight we have
3270 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3271 * Re-arranging gives:
3272 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3274 * For -ve lfHeight we have
3276 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3277 * with il = winAscent + winDescent - units_per_em]
3282 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3283 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3284 pHori
->Ascender
- pHori
->Descender
);
3286 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3287 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3295 static struct font_mapping
*map_font_file( const char *name
)
3297 struct font_mapping
*mapping
;
3301 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3302 if (fstat( fd
, &st
) == -1) goto error
;
3304 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3306 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3308 mapping
->refcount
++;
3313 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3316 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3319 if (mapping
->data
== MAP_FAILED
)
3321 HeapFree( GetProcessHeap(), 0, mapping
);
3324 mapping
->refcount
= 1;
3325 mapping
->dev
= st
.st_dev
;
3326 mapping
->ino
= st
.st_ino
;
3327 mapping
->size
= st
.st_size
;
3328 list_add_tail( &mappings_list
, &mapping
->entry
);
3336 static void unmap_font_file( struct font_mapping
*mapping
)
3338 if (!--mapping
->refcount
)
3340 list_remove( &mapping
->entry
);
3341 munmap( mapping
->data
, mapping
->size
);
3342 HeapFree( GetProcessHeap(), 0, mapping
);
3346 static LONG
load_VDMX(GdiFont
*, LONG
);
3348 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3355 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3359 if (!(font
->mapping
= map_font_file( face
->file
)))
3361 WARN("failed to map %s\n", debugstr_a(face
->file
));
3364 data_ptr
= font
->mapping
->data
;
3365 data_size
= font
->mapping
->size
;
3369 data_ptr
= face
->font_data_ptr
;
3370 data_size
= face
->font_data_size
;
3373 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3375 ERR("FT_New_Face rets %d\n", err
);
3379 /* set it here, as load_VDMX needs it */
3380 font
->ft_face
= ft_face
;
3382 if(FT_IS_SCALABLE(ft_face
)) {
3383 /* load the VDMX table if we have one */
3384 font
->ppem
= load_VDMX(font
, height
);
3386 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3387 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3389 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3390 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3392 font
->ppem
= height
;
3393 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3394 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3400 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3402 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3403 a single face with the requested charset. The idea is to check if
3404 the selected font supports the current ANSI codepage, if it does
3405 return the corresponding charset, else return the first charset */
3408 int acp
= GetACP(), i
;
3412 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3414 const SYSTEM_LINKS
*font_link
;
3416 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
3417 return csi
.ciCharset
;
3419 font_link
= find_font_link(family_name
);
3420 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
3421 return csi
.ciCharset
;
3424 for(i
= 0; i
< 32; i
++) {
3426 if(face
->fs
.fsCsb
[0] & fs0
) {
3427 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3429 return csi
.ciCharset
;
3432 FIXME("TCI failing on %x\n", fs0
);
3436 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3437 face
->fs
.fsCsb
[0], face
->file
);
3439 return DEFAULT_CHARSET
;
3442 static GdiFont
*alloc_font(void)
3444 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3446 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3447 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3449 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3450 ret
->total_kern_pairs
= (DWORD
)-1;
3451 ret
->kern_pairs
= NULL
;
3452 list_init(&ret
->hfontlist
);
3453 list_init(&ret
->child_fonts
);
3457 static void free_font(GdiFont
*font
)
3459 struct list
*cursor
, *cursor2
;
3462 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3464 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3465 list_remove(cursor
);
3467 free_font(child
->font
);
3468 HeapFree(GetProcessHeap(), 0, child
);
3471 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3473 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3474 DeleteObject(hfontlist
->hfont
);
3475 list_remove(&hfontlist
->entry
);
3476 HeapFree(GetProcessHeap(), 0, hfontlist
);
3479 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3480 if (font
->mapping
) unmap_font_file( font
->mapping
);
3481 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3482 HeapFree(GetProcessHeap(), 0, font
->potm
);
3483 HeapFree(GetProcessHeap(), 0, font
->name
);
3484 for (i
= 0; i
< font
->gmsize
; i
++)
3485 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3486 HeapFree(GetProcessHeap(), 0, font
->gm
);
3487 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3488 HeapFree(GetProcessHeap(), 0, font
);
3492 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3494 FT_Face ft_face
= font
->ft_face
;
3498 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3505 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3507 /* make sure value of len is the value freetype says it needs */
3510 FT_ULong needed
= 0;
3511 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3512 if( !err
&& needed
< len
) len
= needed
;
3514 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3517 TRACE("Can't find table %c%c%c%c\n",
3518 /* bytes were reversed */
3519 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3520 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3526 /*************************************************************
3529 * load the vdmx entry for the specified height
3532 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3533 ( ( (FT_ULong)_x4 << 24 ) | \
3534 ( (FT_ULong)_x3 << 16 ) | \
3535 ( (FT_ULong)_x2 << 8 ) | \
3538 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3553 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3557 BYTE devXRatio
, devYRatio
;
3558 USHORT numRecs
, numRatios
;
3559 DWORD result
, offset
= -1;
3563 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3565 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3568 /* FIXME: need the real device aspect ratio */
3572 numRecs
= GET_BE_WORD(hdr
[1]);
3573 numRatios
= GET_BE_WORD(hdr
[2]);
3575 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3576 for(i
= 0; i
< numRatios
; i
++) {
3579 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3580 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3583 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3585 if((ratio
.xRatio
== 0 &&
3586 ratio
.yStartRatio
== 0 &&
3587 ratio
.yEndRatio
== 0) ||
3588 (devXRatio
== ratio
.xRatio
&&
3589 devYRatio
>= ratio
.yStartRatio
&&
3590 devYRatio
<= ratio
.yEndRatio
))
3592 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3593 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3594 offset
= GET_BE_WORD(tmp
);
3600 FIXME("No suitable ratio found\n");
3604 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3606 BYTE startsz
, endsz
;
3609 recs
= GET_BE_WORD(group
.recs
);
3610 startsz
= group
.startsz
;
3611 endsz
= group
.endsz
;
3613 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3615 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3616 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3617 if(result
== GDI_ERROR
) {
3618 FIXME("Failed to retrieve vTable\n");
3623 for(i
= 0; i
< recs
; i
++) {
3624 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3625 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3626 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3628 if(yMax
+ -yMin
== height
) {
3631 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3634 if(yMax
+ -yMin
> height
) {
3637 goto end
; /* failed */
3639 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3640 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3641 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3642 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3648 TRACE("ppem not found for height %d\n", height
);
3652 HeapFree(GetProcessHeap(), 0, vTable
);
3658 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3660 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3661 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3662 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3663 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3664 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3667 static void calc_hash(FONT_DESC
*pfd
)
3669 DWORD hash
= 0, *ptr
, two_chars
;
3673 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3675 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3677 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3679 pwc
= (WCHAR
*)&two_chars
;
3681 *pwc
= toupperW(*pwc
);
3683 *pwc
= toupperW(*pwc
);
3687 hash
^= !pfd
->can_use_bitmap
;
3692 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3697 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3701 fd
.can_use_bitmap
= can_use_bitmap
;
3704 /* try the child list */
3705 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3706 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3707 if(!fontcmp(ret
, &fd
)) {
3708 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3709 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3710 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3711 if(hflist
->hfont
== hfont
)
3717 /* try the in-use list */
3718 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3719 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3720 if(!fontcmp(ret
, &fd
)) {
3721 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3722 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3723 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3724 if(hflist
->hfont
== hfont
)
3727 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3728 hflist
->hfont
= hfont
;
3729 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3734 /* then the unused list */
3735 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3736 while(font_elem_ptr
) {
3737 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3738 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3739 if(!fontcmp(ret
, &fd
)) {
3740 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3741 assert(list_empty(&ret
->hfontlist
));
3742 TRACE("Found %p in unused list\n", ret
);
3743 list_remove(&ret
->entry
);
3744 list_add_head(&gdi_font_list
, &ret
->entry
);
3745 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3746 hflist
->hfont
= hfont
;
3747 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3754 static void add_to_cache(GdiFont
*font
)
3756 static DWORD cache_num
= 1;
3758 font
->cache_num
= cache_num
++;
3759 list_add_head(&gdi_font_list
, &font
->entry
);
3762 /*************************************************************
3763 * create_child_font_list
3765 static BOOL
create_child_font_list(GdiFont
*font
)
3768 SYSTEM_LINKS
*font_link
;
3769 CHILD_FONT
*font_link_entry
, *new_child
;
3773 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3774 font_name
= psub
? psub
->to
.name
: font
->name
;
3775 font_link
= find_font_link(font_name
);
3776 if (font_link
!= NULL
)
3778 TRACE("found entry in system list\n");
3779 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3781 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3782 new_child
->face
= font_link_entry
->face
;
3783 new_child
->font
= NULL
;
3784 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3785 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3790 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3791 * Sans Serif. This is how asian windows get default fallbacks for fonts
3793 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3794 font
->charset
!= OEM_CHARSET
&&
3795 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3797 font_link
= find_font_link(szDefaultFallbackLink
);
3798 if (font_link
!= NULL
)
3800 TRACE("found entry in default fallback list\n");
3801 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3803 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3804 new_child
->face
= font_link_entry
->face
;
3805 new_child
->font
= NULL
;
3806 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3807 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3816 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3818 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3820 if (pFT_Set_Charmap
)
3823 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3825 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3827 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3829 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3831 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3832 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3834 switch (ft_face
->charmaps
[i
]->platform_id
)
3837 cmap_def
= ft_face
->charmaps
[i
];
3839 case 0: /* Apple Unicode */
3840 cmap0
= ft_face
->charmaps
[i
];
3842 case 1: /* Macintosh */
3843 cmap1
= ft_face
->charmaps
[i
];
3846 cmap2
= ft_face
->charmaps
[i
];
3848 case 3: /* Microsoft */
3849 cmap3
= ft_face
->charmaps
[i
];
3854 if (cmap3
) /* prefer Microsoft cmap table */
3855 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3857 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3859 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3861 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3863 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3865 return ft_err
== FT_Err_Ok
;
3868 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3872 /*************************************************************
3875 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
3876 LPCWSTR output
, const DEVMODEW
*devmode
)
3878 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
3880 if (!physdev
) return FALSE
;
3881 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
3886 /*************************************************************
3889 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
3891 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3892 HeapFree( GetProcessHeap(), 0, physdev
);
3897 /*************************************************************
3898 * freetype_SelectFont
3900 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
3902 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3904 Face
*face
, *best
, *best_bitmap
;
3905 Family
*family
, *last_resort_family
;
3906 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
3907 INT height
, width
= 0;
3908 unsigned int score
= 0, new_score
;
3909 signed int diff
= 0, newdiff
;
3910 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
3915 FontSubst
*psub
= NULL
;
3916 DC
*dc
= get_dc_ptr( dev
->hdc
);
3917 const SYSTEM_LINKS
*font_link
;
3919 if (!hfont
) /* notification that the font has been changed by another driver */
3922 physdev
->font
= NULL
;
3923 release_dc_ptr( dc
);
3927 GetObjectW( hfont
, sizeof(lf
), &lf
);
3928 lf
.lfWidth
= abs(lf
.lfWidth
);
3930 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
3932 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3933 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3934 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3937 if(dc
->GraphicsMode
== GM_ADVANCED
)
3939 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3940 /* Try to avoid not necessary glyph transformations */
3941 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3943 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3944 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3945 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3950 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3951 font scaling abilities. */
3952 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3953 dcmat
.eM21
= dcmat
.eM12
= 0;
3954 if (dc
->vport2WorldValid
)
3956 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
3957 lf
.lfOrientation
= -lf
.lfOrientation
;
3958 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
3959 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
3963 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3964 dcmat
.eM21
, dcmat
.eM22
);
3967 EnterCriticalSection( &freetype_cs
);
3969 /* check the cache first */
3970 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3971 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3975 if(list_empty(&font_list
)) /* No fonts installed */
3977 TRACE("No fonts installed\n");
3981 TRACE("not in cache\n");
3984 ret
->font_desc
.matrix
= dcmat
;
3985 ret
->font_desc
.lf
= lf
;
3986 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3987 calc_hash(&ret
->font_desc
);
3988 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3989 hflist
->hfont
= hfont
;
3990 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3992 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3993 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3994 original value lfCharSet. Note this is a special case for
3995 Symbol and doesn't happen at least for "Wingdings*" */
3997 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3998 lf
.lfCharSet
= SYMBOL_CHARSET
;
4000 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4001 switch(lf
.lfCharSet
) {
4002 case DEFAULT_CHARSET
:
4003 csi
.fs
.fsCsb
[0] = 0;
4006 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4007 csi
.fs
.fsCsb
[0] = 0;
4013 if(lf
.lfFaceName
[0] != '\0') {
4014 CHILD_FONT
*font_link_entry
;
4015 LPWSTR FaceName
= lf
.lfFaceName
;
4017 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4020 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4021 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4022 if (psub
->to
.charset
!= -1)
4023 lf
.lfCharSet
= psub
->to
.charset
;
4026 /* We want a match on name and charset or just name if
4027 charset was DEFAULT_CHARSET. If the latter then
4028 we fixup the returned charset later in get_nearest_charset
4029 where we'll either use the charset of the current ansi codepage
4030 or if that's unavailable the first charset that the font supports.
4032 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4033 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4034 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4035 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4037 font_link
= find_font_link(family
->FamilyName
);
4038 face_list
= get_face_list_from_family(family
);
4039 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4040 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4041 if (!(face
->scalable
|| can_use_bitmap
))
4043 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4045 if (font_link
!= NULL
&&
4046 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4048 if (!csi
.fs
.fsCsb
[0])
4054 /* Search by full face name. */
4055 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4056 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4057 face_list
= get_face_list_from_family(family
);
4058 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4059 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4060 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4061 (face
->scalable
|| can_use_bitmap
))
4063 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4065 font_link
= find_font_link(family
->FamilyName
);
4066 if (font_link
!= NULL
&&
4067 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4074 * Try check the SystemLink list first for a replacement font.
4075 * We may find good replacements there.
4077 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4079 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4080 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4082 TRACE("found entry in system list\n");
4083 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4085 const SYSTEM_LINKS
*links
;
4087 face
= font_link_entry
->face
;
4088 if (!(face
->scalable
|| can_use_bitmap
))
4090 family
= face
->family
;
4091 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4093 links
= find_font_link(family
->FamilyName
);
4094 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4101 psub
= NULL
; /* substitution is no more relevant */
4103 /* If requested charset was DEFAULT_CHARSET then try using charset
4104 corresponding to the current ansi codepage */
4105 if (!csi
.fs
.fsCsb
[0])
4108 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4109 FIXME("TCI failed on codepage %d\n", acp
);
4110 csi
.fs
.fsCsb
[0] = 0;
4112 lf
.lfCharSet
= csi
.ciCharset
;
4115 want_vertical
= (lf
.lfFaceName
[0] == '@');
4117 /* Face families are in the top 4 bits of lfPitchAndFamily,
4118 so mask with 0xF0 before testing */
4120 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4121 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4122 strcpyW(lf
.lfFaceName
, defFixed
);
4123 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4124 strcpyW(lf
.lfFaceName
, defSerif
);
4125 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4126 strcpyW(lf
.lfFaceName
, defSans
);
4128 strcpyW(lf
.lfFaceName
, defSans
);
4129 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4130 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4131 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4132 font_link
= find_font_link(family
->FamilyName
);
4133 face_list
= get_face_list_from_family(family
);
4134 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4135 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4136 if (!(face
->scalable
|| can_use_bitmap
))
4138 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4140 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4146 last_resort_family
= NULL
;
4147 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4148 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4149 font_link
= find_font_link(family
->FamilyName
);
4150 face_list
= get_face_list_from_family(family
);
4151 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4152 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4153 if(face
->vertical
== want_vertical
&&
4154 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4155 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4158 if(can_use_bitmap
&& !last_resort_family
)
4159 last_resort_family
= family
;
4164 if(last_resort_family
) {
4165 family
= last_resort_family
;
4166 csi
.fs
.fsCsb
[0] = 0;
4170 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4171 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4172 face_list
= get_face_list_from_family(family
);
4173 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4174 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4175 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4176 csi
.fs
.fsCsb
[0] = 0;
4177 WARN("just using first face for now\n");
4180 if(can_use_bitmap
&& !last_resort_family
)
4181 last_resort_family
= family
;
4184 if(!last_resort_family
) {
4185 FIXME("can't find a single appropriate font - bailing\n");
4191 WARN("could only find a bitmap font - this will probably look awful!\n");
4192 family
= last_resort_family
;
4193 csi
.fs
.fsCsb
[0] = 0;
4196 it
= lf
.lfItalic
? 1 : 0;
4197 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4199 height
= lf
.lfHeight
;
4201 face
= best
= best_bitmap
= NULL
;
4202 font_link
= find_font_link(family
->FamilyName
);
4203 face_list
= get_face_list_from_family(family
);
4204 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4206 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4207 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4212 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4213 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4214 new_score
= (italic
^ it
) + (bold
^ bd
);
4215 if(!best
|| new_score
<= score
)
4217 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4218 italic
, bold
, it
, bd
);
4221 if(best
->scalable
&& score
== 0) break;
4225 newdiff
= height
- (signed int)(best
->size
.height
);
4227 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4228 if(!best_bitmap
|| new_score
< score
||
4229 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4231 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4234 if(score
== 0 && diff
== 0) break;
4241 face
= best
->scalable
? best
: best_bitmap
;
4242 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4243 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4246 height
= lf
.lfHeight
;
4250 if(csi
.fs
.fsCsb
[0]) {
4251 ret
->charset
= lf
.lfCharSet
;
4252 ret
->codepage
= csi
.ciACP
;
4255 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4257 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4258 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4260 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4262 if(!face
->scalable
) {
4263 /* Windows uses integer scaling factors for bitmap fonts */
4264 INT scale
, scaled_height
;
4265 GdiFont
*cachedfont
;
4267 /* FIXME: rotation of bitmap fonts is ignored */
4268 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4270 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4271 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4272 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4273 /* As we changed the matrix, we need to search the cache for the font again,
4274 * otherwise we might explode the cache. */
4275 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4276 TRACE("Found cached font after non-scalable matrix rescale!\n");
4281 calc_hash(&ret
->font_desc
);
4283 if (height
!= 0) height
= diff
;
4284 height
+= face
->size
.height
;
4286 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4287 scaled_height
= scale
* face
->size
.height
;
4288 /* Only jump to the next height if the difference <= 25% original height */
4289 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4290 /* The jump between unscaled and doubled is delayed by 1 */
4291 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4292 ret
->scale_y
= scale
;
4294 width
= face
->size
.x_ppem
>> 6;
4295 height
= face
->size
.y_ppem
>> 6;
4299 TRACE("font scale y: %f\n", ret
->scale_y
);
4301 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4310 ret
->ntmFlags
= face
->ntmFlags
;
4312 if (ret
->charset
== SYMBOL_CHARSET
&&
4313 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4316 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4320 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4323 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4324 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4325 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4326 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4327 create_child_font_list(ret
);
4329 if (face
->vertical
) /* We need to try to load the GSUB table */
4331 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4332 if (length
!= GDI_ERROR
)
4334 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4335 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4336 TRACE("Loaded GSUB table of %i bytes\n",length
);
4340 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4347 physdev
->font
= ret
;
4349 LeaveCriticalSection( &freetype_cs
);
4350 release_dc_ptr( dc
);
4351 return ret
? hfont
: 0;
4354 static void dump_gdi_font_list(void)
4357 struct list
*elem_ptr
;
4359 TRACE("---------- gdiFont Cache ----------\n");
4360 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4361 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4362 TRACE("gdiFont=%p %s %d\n",
4363 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4366 TRACE("---------- Unused gdiFont Cache ----------\n");
4367 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4368 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4369 TRACE("gdiFont=%p %s %d\n",
4370 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4373 TRACE("---------- Child gdiFont Cache ----------\n");
4374 LIST_FOR_EACH(elem_ptr
, &child_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
);
4381 /*************************************************************
4382 * WineEngDestroyFontInstance
4384 * free the gdiFont associated with this handle
4387 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4392 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4396 EnterCriticalSection( &freetype_cs
);
4398 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4400 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4401 while(hfontlist_elem_ptr
) {
4402 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4403 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4404 if(hflist
->hfont
== handle
) {
4405 TRACE("removing child font %p from child list\n", gdiFont
);
4406 list_remove(&gdiFont
->entry
);
4407 LeaveCriticalSection( &freetype_cs
);
4413 TRACE("destroying hfont=%p\n", handle
);
4415 dump_gdi_font_list();
4417 font_elem_ptr
= list_head(&gdi_font_list
);
4418 while(font_elem_ptr
) {
4419 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4420 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4422 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4423 while(hfontlist_elem_ptr
) {
4424 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4425 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4426 if(hflist
->hfont
== handle
) {
4427 list_remove(&hflist
->entry
);
4428 HeapFree(GetProcessHeap(), 0, hflist
);
4432 if(list_empty(&gdiFont
->hfontlist
)) {
4433 TRACE("Moving to Unused list\n");
4434 list_remove(&gdiFont
->entry
);
4435 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4440 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4441 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4442 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4443 while(font_elem_ptr
) {
4444 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4445 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4446 TRACE("freeing %p\n", gdiFont
);
4447 list_remove(&gdiFont
->entry
);
4450 LeaveCriticalSection( &freetype_cs
);
4454 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4461 id
+= IDS_FIRST_SCRIPT
;
4462 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4463 if (!rsrc
) return 0;
4464 hMem
= LoadResource( gdi32_module
, rsrc
);
4465 if (!hMem
) return 0;
4467 p
= LockResource( hMem
);
4469 while (id
--) p
+= *p
+ 1;
4471 i
= min(LF_FACESIZE
- 1, *p
);
4472 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4478 /***************************************************
4479 * create_enum_charset_list
4481 * This function creates charset enumeration list because in DEFAULT_CHARSET
4482 * case, the ANSI codepage's charset takes precedence over other charsets.
4483 * This function works as a filter other than DEFAULT_CHARSET case.
4485 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4490 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4491 csi
.fs
.fsCsb
[0] != 0) {
4492 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4493 list
->element
[n
].charset
= csi
.ciCharset
;
4494 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4497 else { /* charset is DEFAULT_CHARSET or invalid. */
4500 /* Set the current codepage's charset as the first element. */
4502 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4503 csi
.fs
.fsCsb
[0] != 0) {
4504 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4505 list
->element
[n
].charset
= csi
.ciCharset
;
4506 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4510 /* Fill out left elements. */
4511 for (i
= 0; i
< 32; i
++) {
4513 fs
.fsCsb
[0] = 1L << i
;
4515 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4516 continue; /* skip, already added. */
4517 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4518 continue; /* skip, this is an invalid fsCsb bit. */
4520 list
->element
[n
].mask
= fs
.fsCsb
[0];
4521 list
->element
[n
].charset
= csi
.ciCharset
;
4522 load_script_name( i
, list
->element
[n
].name
);
4531 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4532 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4537 if (face
->cached_enum_data
)
4540 *pelf
= face
->cached_enum_data
->elf
;
4541 *pntm
= face
->cached_enum_data
->ntm
;
4542 *ptype
= face
->cached_enum_data
->type
;
4546 font
= alloc_font();
4548 if(face
->scalable
) {
4549 height
= -2048; /* 2048 is the most common em size */
4552 height
= face
->size
.y_ppem
>> 6;
4553 width
= face
->size
.x_ppem
>> 6;
4555 font
->scale_y
= 1.0;
4557 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4563 font
->name
= strdupW(face
->family
->FamilyName
);
4564 font
->ntmFlags
= face
->ntmFlags
;
4566 if (get_outline_text_metrics(font
))
4568 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4570 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4572 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4573 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4575 lstrcpynW(pelf
->elfFullName
,
4576 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4578 lstrcpynW(pelf
->elfStyle
,
4579 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4584 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4586 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4588 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4590 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4592 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4593 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4596 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4597 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4598 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4599 pntm
->ntmFontSig
= face
->fs
;
4601 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4603 pelf
->elfLogFont
.lfEscapement
= 0;
4604 pelf
->elfLogFont
.lfOrientation
= 0;
4605 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4606 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4607 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4608 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4609 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4610 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4611 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4612 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4613 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4614 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4615 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4618 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4619 *ptype
|= TRUETYPE_FONTTYPE
;
4620 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4621 *ptype
|= DEVICE_FONTTYPE
;
4622 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4623 *ptype
|= RASTER_FONTTYPE
;
4625 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4626 if (face
->cached_enum_data
)
4628 face
->cached_enum_data
->elf
= *pelf
;
4629 face
->cached_enum_data
->ntm
= *pntm
;
4630 face
->cached_enum_data
->type
= *ptype
;
4636 static void create_full_name(WCHAR
*full_name
, const WCHAR
*family_name
, const WCHAR
*style_name
)
4638 static const WCHAR spaceW
[] = { ' ', 0 };
4640 strcpyW(full_name
, family_name
);
4641 strcatW(full_name
, spaceW
);
4642 strcatW(full_name
, style_name
);
4645 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4647 const struct list
*face_list
, *face_elem_ptr
;
4649 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4651 face_list
= get_face_list_from_family(family
);
4652 LIST_FOR_EACH(face_elem_ptr
, face_list
)
4654 WCHAR full_family_name
[LF_FULLFACESIZE
];
4655 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4657 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4659 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4660 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4664 create_full_name(full_family_name
, family
->FamilyName
, face
->StyleName
);
4665 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4671 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
4673 WCHAR full_family_name
[LF_FULLFACESIZE
];
4675 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
4677 if (strlenW(family_name
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4679 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4680 debugstr_w(family_name
), debugstr_w(face
->StyleName
));
4684 create_full_name(full_family_name
, family_name
, face
->StyleName
);
4685 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4688 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
4689 FONTENUMPROCW proc
, LPARAM lparam
)
4692 NEWTEXTMETRICEXW ntm
;
4696 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4697 for(i
= 0; i
< list
->total
; i
++) {
4698 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4699 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4700 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4701 i
= list
->total
; /* break out of loop after enumeration */
4702 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4705 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4706 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4707 if (!elf
.elfScript
[0])
4708 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4710 /* Font Replacement */
4711 if (family
!= face
->family
)
4713 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
4714 create_full_name(elf
.elfFullName
, family
->FamilyName
, face
->StyleName
);
4716 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4717 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4718 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4719 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4720 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4721 ntm
.ntmTm
.ntmFlags
);
4722 /* release section before callback (FIXME) */
4723 LeaveCriticalSection( &freetype_cs
);
4724 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4725 EnterCriticalSection( &freetype_cs
);
4730 /*************************************************************
4731 * freetype_EnumFonts
4733 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4737 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4739 struct enum_charset_list enum_charsets
;
4743 lf
.lfCharSet
= DEFAULT_CHARSET
;
4744 lf
.lfPitchAndFamily
= 0;
4745 lf
.lfFaceName
[0] = 0;
4749 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4751 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4754 EnterCriticalSection( &freetype_cs
);
4755 if(plf
->lfFaceName
[0]) {
4757 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4760 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4761 debugstr_w(psub
->to
.name
));
4763 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4767 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4768 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4769 if(family_matches(family
, plf
)) {
4770 face_list
= get_face_list_from_family(family
);
4771 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4772 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4773 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
4774 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4779 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4780 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4781 face_list
= get_face_list_from_family(family
);
4782 face_elem_ptr
= list_head(face_list
);
4783 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4784 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4787 LeaveCriticalSection( &freetype_cs
);
4791 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4793 pt
->x
.value
= vec
->x
>> 6;
4794 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4795 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4796 pt
->y
.value
= vec
->y
>> 6;
4797 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4798 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4802 /***************************************************
4803 * According to the MSDN documentation on WideCharToMultiByte,
4804 * certain codepages cannot set the default_used parameter.
4805 * This returns TRUE if the codepage can set that parameter, false else
4806 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4808 static BOOL
codepage_sets_default_used(UINT codepage
)
4822 * GSUB Table handling functions
4825 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4827 const GSUB_CoverageFormat1
* cf1
;
4831 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4833 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4835 TRACE("Coverage Format 1, %i glyphs\n",count
);
4836 for (i
= 0; i
< count
; i
++)
4837 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4841 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4843 const GSUB_CoverageFormat2
* cf2
;
4846 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4848 count
= GET_BE_WORD(cf2
->RangeCount
);
4849 TRACE("Coverage Format 2, %i ranges\n",count
);
4850 for (i
= 0; i
< count
; i
++)
4852 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4854 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4855 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4857 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4858 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4864 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4869 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4871 const GSUB_ScriptList
*script
;
4872 const GSUB_Script
*deflt
= NULL
;
4874 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4876 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4877 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4879 const GSUB_Script
*scr
;
4882 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4883 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4885 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4887 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4893 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4897 const GSUB_LangSys
*Lang
;
4899 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4901 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4903 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4904 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4906 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4909 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4912 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4918 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4921 const GSUB_FeatureList
*feature
;
4922 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4924 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4925 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4927 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4928 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4930 const GSUB_Feature
*feat
;
4931 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4938 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4942 const GSUB_LookupList
*lookup
;
4943 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4945 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4946 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4948 const GSUB_LookupTable
*look
;
4949 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4950 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4951 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4952 if (GET_BE_WORD(look
->LookupType
) != 1)
4953 FIXME("We only handle SubType 1\n");
4958 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4960 const GSUB_SingleSubstFormat1
*ssf1
;
4961 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4962 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4963 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4965 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4966 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4967 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4969 TRACE(" Glyph 0x%x ->",glyph
);
4970 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4971 TRACE(" 0x%x\n",glyph
);
4976 const GSUB_SingleSubstFormat2
*ssf2
;
4980 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4981 offset
= GET_BE_WORD(ssf1
->Coverage
);
4982 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4983 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4984 TRACE(" Coverage index %i\n",index
);
4987 TRACE(" Glyph is 0x%x ->",glyph
);
4988 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4989 TRACE("0x%x\n",glyph
);
4998 static const char* get_opentype_script(const GdiFont
*font
)
5001 * I am not sure if this is the correct way to generate our script tag
5004 switch (font
->charset
)
5006 case ANSI_CHARSET
: return "latn";
5007 case BALTIC_CHARSET
: return "latn"; /* ?? */
5008 case CHINESEBIG5_CHARSET
: return "hani";
5009 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5010 case GB2312_CHARSET
: return "hani";
5011 case GREEK_CHARSET
: return "grek";
5012 case HANGUL_CHARSET
: return "hang";
5013 case RUSSIAN_CHARSET
: return "cyrl";
5014 case SHIFTJIS_CHARSET
: return "kana";
5015 case TURKISH_CHARSET
: return "latn"; /* ?? */
5016 case VIETNAMESE_CHARSET
: return "latn";
5017 case JOHAB_CHARSET
: return "latn"; /* ?? */
5018 case ARABIC_CHARSET
: return "arab";
5019 case HEBREW_CHARSET
: return "hebr";
5020 case THAI_CHARSET
: return "thai";
5021 default: return "latn";
5025 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5027 const GSUB_Header
*header
;
5028 const GSUB_Script
*script
;
5029 const GSUB_LangSys
*language
;
5030 const GSUB_Feature
*feature
;
5032 if (!font
->GSUB_Table
)
5035 header
= font
->GSUB_Table
;
5037 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5040 TRACE("Script not found\n");
5043 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5046 TRACE("Language not found\n");
5049 feature
= GSUB_get_feature(header
, language
, "vrt2");
5051 feature
= GSUB_get_feature(header
, language
, "vert");
5054 TRACE("vrt2/vert feature not found\n");
5057 return GSUB_apply_feature(header
, feature
, glyph
);
5060 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5064 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5065 WCHAR wc
= (WCHAR
)glyph
;
5067 BOOL
*default_used_pointer
;
5070 default_used_pointer
= NULL
;
5071 default_used
= FALSE
;
5072 if (codepage_sets_default_used(font
->codepage
))
5073 default_used_pointer
= &default_used
;
5074 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5077 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5078 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5082 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5084 if (glyph
< 0x100) glyph
+= 0xf000;
5085 /* there is a number of old pre-Unicode "broken" TTFs, which
5086 do have symbols at U+00XX instead of U+f0XX */
5087 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5088 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5090 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5095 /*************************************************************
5096 * freetype_GetGlyphIndices
5098 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5100 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5103 BOOL got_default
= FALSE
;
5107 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5108 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5111 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5113 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5118 EnterCriticalSection( &freetype_cs
);
5120 for(i
= 0; i
< count
; i
++)
5122 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5127 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5129 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5130 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5135 get_text_metrics(physdev
->font
, &textm
);
5136 default_char
= textm
.tmDefaultChar
;
5140 pgi
[i
] = default_char
;
5143 LeaveCriticalSection( &freetype_cs
);
5147 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5149 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5150 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5153 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5155 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5156 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5159 static inline BYTE
get_max_level( UINT format
)
5163 case GGO_GRAY2_BITMAP
: return 4;
5164 case GGO_GRAY4_BITMAP
: return 16;
5165 case GGO_GRAY8_BITMAP
: return 64;
5170 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5172 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5173 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5176 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5177 FT_Face ft_face
= incoming_font
->ft_face
;
5178 GdiFont
*font
= incoming_font
;
5179 FT_UInt glyph_index
;
5180 DWORD width
, height
, pitch
, needed
= 0;
5181 FT_Bitmap ft_bitmap
;
5183 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5185 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5186 double widthRatio
= 1.0;
5187 FT_Matrix transMat
= identityMat
;
5188 FT_Matrix transMatUnrotated
;
5189 BOOL needsTransform
= FALSE
;
5190 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5191 UINT original_index
;
5193 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5194 buflen
, buf
, lpmat
);
5196 TRACE("font transform %f %f %f %f\n",
5197 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5198 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5200 if(format
& GGO_GLYPH_INDEX
) {
5201 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5202 original_index
= glyph
;
5203 format
&= ~GGO_GLYPH_INDEX
;
5205 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5206 ft_face
= font
->ft_face
;
5207 original_index
= glyph_index
;
5210 if(format
& GGO_UNHINTED
) {
5211 load_flags
|= FT_LOAD_NO_HINTING
;
5212 format
&= ~GGO_UNHINTED
;
5215 /* tategaki never appears to happen to lower glyph index */
5216 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5219 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5220 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5221 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5222 font
->gmsize
* sizeof(GM
*));
5224 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5225 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5227 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5228 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5229 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5230 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5231 return 1; /* FIXME */
5235 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5236 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5238 /* Scaling factor */
5243 get_text_metrics(font
, &tm
);
5245 widthRatio
= (double)font
->aveWidth
;
5246 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5249 widthRatio
= font
->scale_y
;
5251 /* Scaling transform */
5252 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5255 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5258 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5260 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5261 needsTransform
= TRUE
;
5264 /* Slant transform */
5265 if (font
->fake_italic
) {
5268 slantMat
.xx
= (1 << 16);
5269 slantMat
.xy
= ((1 << 16) >> 2);
5271 slantMat
.yy
= (1 << 16);
5272 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5273 needsTransform
= TRUE
;
5276 /* Rotation transform */
5277 transMatUnrotated
= transMat
;
5278 if(font
->orientation
&& !tategaki
) {
5279 FT_Matrix rotationMat
;
5281 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5282 pFT_Vector_Unit(&vecAngle
, angle
);
5283 rotationMat
.xx
= vecAngle
.x
;
5284 rotationMat
.xy
= -vecAngle
.y
;
5285 rotationMat
.yx
= -rotationMat
.xy
;
5286 rotationMat
.yy
= rotationMat
.xx
;
5288 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5289 needsTransform
= TRUE
;
5292 /* World transform */
5293 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5296 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5297 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5298 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5299 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5300 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5301 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5302 needsTransform
= TRUE
;
5305 /* Extra transformation specified by caller */
5306 if (!is_identity_MAT2(lpmat
))
5309 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5310 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5311 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5312 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5313 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5314 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5315 needsTransform
= TRUE
;
5318 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5319 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5320 format
== GGO_GRAY8_BITMAP
))
5322 load_flags
|= FT_LOAD_NO_BITMAP
;
5325 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5328 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5332 if(!needsTransform
) {
5333 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5334 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5335 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5337 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5338 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5339 ft_face
->glyph
->metrics
.height
) & -64;
5340 lpgm
->gmCellIncX
= adv
;
5341 lpgm
->gmCellIncY
= 0;
5348 for(xc
= 0; xc
< 2; xc
++) {
5349 for(yc
= 0; yc
< 2; yc
++) {
5350 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5351 xc
* ft_face
->glyph
->metrics
.width
);
5352 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5353 yc
* ft_face
->glyph
->metrics
.height
;
5354 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5355 pFT_Vector_Transform(&vec
, &transMat
);
5356 if(xc
== 0 && yc
== 0) {
5357 left
= right
= vec
.x
;
5358 top
= bottom
= vec
.y
;
5360 if(vec
.x
< left
) left
= vec
.x
;
5361 else if(vec
.x
> right
) right
= vec
.x
;
5362 if(vec
.y
< bottom
) bottom
= vec
.y
;
5363 else if(vec
.y
> top
) top
= vec
.y
;
5368 right
= (right
+ 63) & -64;
5369 bottom
= bottom
& -64;
5370 top
= (top
+ 63) & -64;
5372 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5373 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5375 pFT_Vector_Transform(&vec
, &transMat
);
5376 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5377 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5379 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5381 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5382 adv
= (vec
.x
+63) >> 6;
5386 bbx
= (right
- left
) >> 6;
5387 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5388 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5389 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5390 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5392 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5393 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5394 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5396 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5397 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5399 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5400 FONT_GM(font
,original_index
)->adv
= adv
;
5401 FONT_GM(font
,original_index
)->lsb
= lsb
;
5402 FONT_GM(font
,original_index
)->bbx
= bbx
;
5403 FONT_GM(font
,original_index
)->init
= TRUE
;
5406 if(format
== GGO_METRICS
)
5408 return 1; /* FIXME */
5411 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5412 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5414 TRACE("loaded a bitmap\n");
5420 width
= lpgm
->gmBlackBoxX
;
5421 height
= lpgm
->gmBlackBoxY
;
5422 pitch
= ((width
+ 31) >> 5) << 2;
5423 needed
= pitch
* height
;
5425 if(!buf
|| !buflen
) break;
5427 switch(ft_face
->glyph
->format
) {
5428 case ft_glyph_format_bitmap
:
5430 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5431 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5432 INT h
= ft_face
->glyph
->bitmap
.rows
;
5434 memcpy(dst
, src
, w
);
5435 src
+= ft_face
->glyph
->bitmap
.pitch
;
5441 case ft_glyph_format_outline
:
5442 ft_bitmap
.width
= width
;
5443 ft_bitmap
.rows
= height
;
5444 ft_bitmap
.pitch
= pitch
;
5445 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5446 ft_bitmap
.buffer
= buf
;
5449 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5451 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5453 /* Note: FreeType will only set 'black' bits for us. */
5454 memset(buf
, 0, needed
);
5455 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5459 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5464 case GGO_GRAY2_BITMAP
:
5465 case GGO_GRAY4_BITMAP
:
5466 case GGO_GRAY8_BITMAP
:
5467 case WINE_GGO_GRAY16_BITMAP
:
5469 unsigned int max_level
, row
, col
;
5472 width
= lpgm
->gmBlackBoxX
;
5473 height
= lpgm
->gmBlackBoxY
;
5474 pitch
= (width
+ 3) / 4 * 4;
5475 needed
= pitch
* height
;
5477 if(!buf
|| !buflen
) break;
5479 max_level
= get_max_level( format
);
5481 switch(ft_face
->glyph
->format
) {
5482 case ft_glyph_format_bitmap
:
5484 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5485 INT h
= ft_face
->glyph
->bitmap
.rows
;
5487 memset( buf
, 0, needed
);
5489 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5490 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5491 src
+= ft_face
->glyph
->bitmap
.pitch
;
5496 case ft_glyph_format_outline
:
5498 ft_bitmap
.width
= width
;
5499 ft_bitmap
.rows
= height
;
5500 ft_bitmap
.pitch
= pitch
;
5501 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5502 ft_bitmap
.buffer
= buf
;
5505 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5507 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5509 memset(ft_bitmap
.buffer
, 0, buflen
);
5511 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5513 if (max_level
!= 255)
5515 for (row
= 0, start
= buf
; row
< height
; row
++)
5517 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5518 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5526 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5532 case WINE_GGO_HRGB_BITMAP
:
5533 case WINE_GGO_HBGR_BITMAP
:
5534 case WINE_GGO_VRGB_BITMAP
:
5535 case WINE_GGO_VBGR_BITMAP
:
5536 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5538 switch (ft_face
->glyph
->format
)
5540 case FT_GLYPH_FORMAT_BITMAP
:
5545 width
= lpgm
->gmBlackBoxX
;
5546 height
= lpgm
->gmBlackBoxY
;
5548 needed
= pitch
* height
;
5550 if (!buf
|| !buflen
) break;
5552 memset(buf
, 0, buflen
);
5554 src
= ft_face
->glyph
->bitmap
.buffer
;
5555 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5557 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5560 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5562 if ( src
[x
/ 8] & masks
[x
% 8] )
5563 ((unsigned int *)dst
)[x
] = ~0u;
5572 case FT_GLYPH_FORMAT_OUTLINE
:
5576 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5577 INT x_shift
, y_shift
;
5579 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5580 FT_Render_Mode render_mode
=
5581 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5582 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5584 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5586 if ( render_mode
== FT_RENDER_MODE_LCD
)
5588 lpgm
->gmBlackBoxX
+= 2;
5589 lpgm
->gmptGlyphOrigin
.x
-= 1;
5593 lpgm
->gmBlackBoxY
+= 2;
5594 lpgm
->gmptGlyphOrigin
.y
+= 1;
5598 width
= lpgm
->gmBlackBoxX
;
5599 height
= lpgm
->gmBlackBoxY
;
5601 needed
= pitch
* height
;
5603 if (!buf
|| !buflen
) break;
5605 memset(buf
, 0, buflen
);
5607 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5609 if ( needsTransform
)
5610 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5612 if ( pFT_Library_SetLcdFilter
)
5613 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5614 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5616 src
= ft_face
->glyph
->bitmap
.buffer
;
5617 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5618 src_width
= ft_face
->glyph
->bitmap
.width
;
5619 src_height
= ft_face
->glyph
->bitmap
.rows
;
5621 if ( render_mode
== FT_RENDER_MODE_LCD
)
5629 rgb_interval
= src_pitch
;
5634 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5635 if ( x_shift
< 0 ) x_shift
= 0;
5636 if ( x_shift
+ (src_width
/ hmul
) > width
)
5637 x_shift
= width
- (src_width
/ hmul
);
5639 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5640 if ( y_shift
< 0 ) y_shift
= 0;
5641 if ( y_shift
+ (src_height
/ vmul
) > height
)
5642 y_shift
= height
- (src_height
/ vmul
);
5644 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5645 while ( src_height
)
5647 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5651 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5652 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5653 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5654 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5658 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5659 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5660 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5661 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5664 src
+= src_pitch
* vmul
;
5673 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5685 int contour
, point
= 0, first_pt
;
5686 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5687 TTPOLYGONHEADER
*pph
;
5689 DWORD pph_start
, cpfx
, type
;
5691 if(buflen
== 0) buf
= NULL
;
5693 if (needsTransform
&& buf
) {
5694 pFT_Outline_Transform(outline
, &transMat
);
5697 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5699 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5702 pph
->dwType
= TT_POLYGON_TYPE
;
5703 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5705 needed
+= sizeof(*pph
);
5707 while(point
<= outline
->contours
[contour
]) {
5708 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5709 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5710 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5714 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5717 } while(point
<= outline
->contours
[contour
] &&
5718 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5719 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5720 /* At the end of a contour Windows adds the start point, but
5722 if(point
> outline
->contours
[contour
] &&
5723 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5725 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5727 } else if(point
<= outline
->contours
[contour
] &&
5728 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5729 /* add closing pt for bezier */
5731 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5739 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5742 pph
->cb
= needed
- pph_start
;
5748 /* Convert the quadratic Beziers to cubic Beziers.
5749 The parametric eqn for a cubic Bezier is, from PLRM:
5750 r(t) = at^3 + bt^2 + ct + r0
5751 with the control points:
5756 A quadratic Bezier has the form:
5757 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5759 So equating powers of t leads to:
5760 r1 = 2/3 p1 + 1/3 p0
5761 r2 = 2/3 p1 + 1/3 p2
5762 and of course r0 = p0, r3 = p2
5765 int contour
, point
= 0, first_pt
;
5766 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5767 TTPOLYGONHEADER
*pph
;
5769 DWORD pph_start
, cpfx
, type
;
5770 FT_Vector cubic_control
[4];
5771 if(buflen
== 0) buf
= NULL
;
5773 if (needsTransform
&& buf
) {
5774 pFT_Outline_Transform(outline
, &transMat
);
5777 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5779 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5782 pph
->dwType
= TT_POLYGON_TYPE
;
5783 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5785 needed
+= sizeof(*pph
);
5787 while(point
<= outline
->contours
[contour
]) {
5788 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5789 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5790 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5793 if(type
== TT_PRIM_LINE
) {
5795 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5799 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5802 /* FIXME: Possible optimization in endpoint calculation
5803 if there are two consecutive curves */
5804 cubic_control
[0] = outline
->points
[point
-1];
5805 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5806 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5807 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5808 cubic_control
[0].x
>>= 1;
5809 cubic_control
[0].y
>>= 1;
5811 if(point
+1 > outline
->contours
[contour
])
5812 cubic_control
[3] = outline
->points
[first_pt
];
5814 cubic_control
[3] = outline
->points
[point
+1];
5815 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5816 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5817 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5818 cubic_control
[3].x
>>= 1;
5819 cubic_control
[3].y
>>= 1;
5822 /* r1 = 1/3 p0 + 2/3 p1
5823 r2 = 1/3 p2 + 2/3 p1 */
5824 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5825 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5826 cubic_control
[2] = cubic_control
[1];
5827 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5828 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5829 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5830 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5832 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5833 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5834 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5839 } while(point
<= outline
->contours
[contour
] &&
5840 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5841 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5842 /* At the end of a contour Windows adds the start point,
5843 but only for Beziers and we've already done that.
5845 if(point
<= outline
->contours
[contour
] &&
5846 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5847 /* This is the closing pt of a bezier, but we've already
5848 added it, so just inc point and carry on */
5855 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5858 pph
->cb
= needed
- pph_start
;
5864 FIXME("Unsupported format %d\n", format
);
5870 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5872 FT_Face ft_face
= font
->ft_face
;
5873 FT_WinFNT_HeaderRec winfnt_header
;
5874 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5875 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5876 font
->potm
->otmSize
= size
;
5878 #define TM font->potm->otmTextMetrics
5879 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5881 TM
.tmHeight
= winfnt_header
.pixel_height
;
5882 TM
.tmAscent
= winfnt_header
.ascent
;
5883 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5884 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5885 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5886 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5887 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5888 TM
.tmWeight
= winfnt_header
.weight
;
5890 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5891 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5892 TM
.tmFirstChar
= winfnt_header
.first_char
;
5893 TM
.tmLastChar
= winfnt_header
.last_char
;
5894 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5895 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5896 TM
.tmItalic
= winfnt_header
.italic
;
5897 TM
.tmUnderlined
= font
->underline
;
5898 TM
.tmStruckOut
= font
->strikeout
;
5899 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5900 TM
.tmCharSet
= winfnt_header
.charset
;
5904 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5905 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5906 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5907 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5908 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5909 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5910 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5911 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5913 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5914 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5916 TM
.tmLastChar
= 255;
5917 TM
.tmDefaultChar
= 32;
5918 TM
.tmBreakChar
= 32;
5919 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5920 TM
.tmUnderlined
= font
->underline
;
5921 TM
.tmStruckOut
= font
->strikeout
;
5922 /* NB inverted meaning of TMPF_FIXED_PITCH */
5923 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5924 TM
.tmCharSet
= font
->charset
;
5932 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5934 double scale_x
, scale_y
;
5938 scale_x
= (double)font
->aveWidth
;
5939 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5942 scale_x
= font
->scale_y
;
5944 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5945 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5947 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5948 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5950 SCALE_Y(ptm
->tmHeight
);
5951 SCALE_Y(ptm
->tmAscent
);
5952 SCALE_Y(ptm
->tmDescent
);
5953 SCALE_Y(ptm
->tmInternalLeading
);
5954 SCALE_Y(ptm
->tmExternalLeading
);
5955 SCALE_Y(ptm
->tmOverhang
);
5957 SCALE_X(ptm
->tmAveCharWidth
);
5958 SCALE_X(ptm
->tmMaxCharWidth
);
5964 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5966 double scale_x
, scale_y
;
5970 scale_x
= (double)font
->aveWidth
;
5971 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5974 scale_x
= font
->scale_y
;
5976 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5977 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5979 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5981 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5982 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5984 SCALE_Y(potm
->otmAscent
);
5985 SCALE_Y(potm
->otmDescent
);
5986 SCALE_Y(potm
->otmLineGap
);
5987 SCALE_Y(potm
->otmsCapEmHeight
);
5988 SCALE_Y(potm
->otmsXHeight
);
5989 SCALE_Y(potm
->otmrcFontBox
.top
);
5990 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5991 SCALE_X(potm
->otmrcFontBox
.left
);
5992 SCALE_X(potm
->otmrcFontBox
.right
);
5993 SCALE_Y(potm
->otmMacAscent
);
5994 SCALE_Y(potm
->otmMacDescent
);
5995 SCALE_Y(potm
->otmMacLineGap
);
5996 SCALE_X(potm
->otmptSubscriptSize
.x
);
5997 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5998 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5999 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6000 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6001 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6002 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6003 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6004 SCALE_Y(potm
->otmsStrikeoutSize
);
6005 SCALE_Y(potm
->otmsStrikeoutPosition
);
6006 SCALE_Y(potm
->otmsUnderscoreSize
);
6007 SCALE_Y(potm
->otmsUnderscorePosition
);
6013 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6017 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6019 /* Make sure that the font has sane width/height ratio */
6022 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6024 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6029 *ptm
= font
->potm
->otmTextMetrics
;
6030 scale_font_metrics(font
, ptm
);
6034 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6038 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6040 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6046 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6049 FT_Face ft_face
= font
->ft_face
;
6050 UINT needed
, lenfam
, lensty
;
6052 TT_HoriHeader
*pHori
;
6053 TT_Postscript
*pPost
;
6054 FT_Fixed x_scale
, y_scale
;
6055 WCHAR
*family_nameW
, *style_nameW
;
6056 static const WCHAR spaceW
[] = {' ', '\0'};
6058 INT ascent
, descent
;
6060 TRACE("font=%p\n", font
);
6062 if(!FT_IS_SCALABLE(ft_face
))
6065 needed
= sizeof(*font
->potm
);
6067 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6068 family_nameW
= strdupW(font
->name
);
6070 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6072 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6073 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6074 style_nameW
, lensty
/sizeof(WCHAR
));
6076 /* These names should be read from the TT name table */
6078 /* length of otmpFamilyName */
6081 /* length of otmpFaceName */
6082 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6083 needed
+= lenfam
; /* just the family name */
6085 needed
+= lenfam
+ lensty
; /* family + " " + style */
6088 /* length of otmpStyleName */
6091 /* length of otmpFullName */
6092 needed
+= lenfam
+ lensty
;
6095 x_scale
= ft_face
->size
->metrics
.x_scale
;
6096 y_scale
= ft_face
->size
->metrics
.y_scale
;
6098 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6100 FIXME("Can't find OS/2 table - not TT font?\n");
6104 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6106 FIXME("Can't find HHEA table - not TT font?\n");
6110 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6112 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",
6113 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6114 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6115 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6116 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6117 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6119 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6120 font
->potm
->otmSize
= needed
;
6122 #define TM font->potm->otmTextMetrics
6124 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6125 ascent
= pHori
->Ascender
;
6126 descent
= -pHori
->Descender
;
6128 ascent
= pOS2
->usWinAscent
;
6129 descent
= pOS2
->usWinDescent
;
6133 TM
.tmAscent
= font
->yMax
;
6134 TM
.tmDescent
= -font
->yMin
;
6135 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6137 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6138 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6139 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6140 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6143 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6146 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6148 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6149 ((ascent
+ descent
) -
6150 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6152 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6153 if (TM
.tmAveCharWidth
== 0) {
6154 TM
.tmAveCharWidth
= 1;
6156 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6157 TM
.tmWeight
= FW_REGULAR
;
6158 if (font
->fake_bold
)
6159 TM
.tmWeight
= FW_BOLD
;
6162 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6164 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6165 TM
.tmWeight
= pOS2
->usWeightClass
;
6167 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6168 TM
.tmWeight
= pOS2
->usWeightClass
;
6171 TM
.tmDigitizedAspectX
= 300;
6172 TM
.tmDigitizedAspectY
= 300;
6173 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6174 * symbol range to 0 - f0ff
6177 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6182 case 1257: /* Baltic */
6183 TM
.tmLastChar
= 0xf8fd;
6186 TM
.tmLastChar
= 0xf0ff;
6188 TM
.tmBreakChar
= 0x20;
6189 TM
.tmDefaultChar
= 0x1f;
6193 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6194 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6196 if(pOS2
->usFirstCharIndex
<= 1)
6197 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6198 else if (pOS2
->usFirstCharIndex
> 0xff)
6199 TM
.tmBreakChar
= 0x20;
6201 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6202 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6204 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6205 TM
.tmUnderlined
= font
->underline
;
6206 TM
.tmStruckOut
= font
->strikeout
;
6208 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6209 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6210 (pOS2
->version
== 0xFFFFU
||
6211 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6212 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6214 TM
.tmPitchAndFamily
= 0;
6216 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6218 case PAN_FAMILY_SCRIPT
:
6219 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6222 case PAN_FAMILY_DECORATIVE
:
6223 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6228 case PAN_FAMILY_TEXT_DISPLAY
:
6229 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6230 /* which is clearly not what the panose spec says. */
6232 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6233 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6234 TM
.tmPitchAndFamily
= FF_MODERN
;
6237 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6242 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6245 case PAN_SERIF_COVE
:
6246 case PAN_SERIF_OBTUSE_COVE
:
6247 case PAN_SERIF_SQUARE_COVE
:
6248 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6249 case PAN_SERIF_SQUARE
:
6250 case PAN_SERIF_THIN
:
6251 case PAN_SERIF_BONE
:
6252 case PAN_SERIF_EXAGGERATED
:
6253 case PAN_SERIF_TRIANGLE
:
6254 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6257 case PAN_SERIF_NORMAL_SANS
:
6258 case PAN_SERIF_OBTUSE_SANS
:
6259 case PAN_SERIF_PERP_SANS
:
6260 case PAN_SERIF_FLARED
:
6261 case PAN_SERIF_ROUNDED
:
6262 TM
.tmPitchAndFamily
|= FF_SWISS
;
6269 if(FT_IS_SCALABLE(ft_face
))
6270 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6272 if(FT_IS_SFNT(ft_face
))
6274 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6275 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6277 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6280 TM
.tmCharSet
= font
->charset
;
6282 font
->potm
->otmFiller
= 0;
6283 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6284 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6285 font
->potm
->otmfsType
= pOS2
->fsType
;
6286 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6287 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6288 font
->potm
->otmItalicAngle
= 0; /* POST table */
6289 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6290 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6291 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6292 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6293 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6294 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6295 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6296 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6297 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6298 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6299 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6300 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6301 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6302 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6303 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6304 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6305 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6306 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6307 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6308 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6309 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6310 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6311 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6312 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6314 font
->potm
->otmsUnderscoreSize
= 0;
6315 font
->potm
->otmsUnderscorePosition
= 0;
6317 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6318 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6322 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6323 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6324 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6325 strcpyW((WCHAR
*)cp
, family_nameW
);
6327 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6328 strcpyW((WCHAR
*)cp
, style_nameW
);
6330 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6331 strcpyW((WCHAR
*)cp
, family_nameW
);
6332 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6333 strcatW((WCHAR
*)cp
, spaceW
);
6334 strcatW((WCHAR
*)cp
, style_nameW
);
6335 cp
+= lenfam
+ lensty
;
6338 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6339 strcpyW((WCHAR
*)cp
, family_nameW
);
6340 strcatW((WCHAR
*)cp
, spaceW
);
6341 strcatW((WCHAR
*)cp
, style_nameW
);
6345 HeapFree(GetProcessHeap(), 0, style_nameW
);
6346 HeapFree(GetProcessHeap(), 0, family_nameW
);
6350 /*************************************************************
6351 * freetype_GetGlyphOutline
6353 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6354 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6356 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6361 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6362 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6366 EnterCriticalSection( &freetype_cs
);
6367 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6368 LeaveCriticalSection( &freetype_cs
);
6372 /*************************************************************
6373 * freetype_GetTextMetrics
6375 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6377 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6382 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6383 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6387 EnterCriticalSection( &freetype_cs
);
6388 ret
= get_text_metrics( physdev
->font
, metrics
);
6389 LeaveCriticalSection( &freetype_cs
);
6393 /*************************************************************
6394 * freetype_GetOutlineTextMetrics
6396 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6398 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6403 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6404 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6407 TRACE("font=%p\n", physdev
->font
);
6409 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6412 EnterCriticalSection( &freetype_cs
);
6414 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6416 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6418 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6419 scale_outline_font_metrics(physdev
->font
, potm
);
6421 ret
= physdev
->font
->potm
->otmSize
;
6423 LeaveCriticalSection( &freetype_cs
);
6427 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6429 HFONTLIST
*hfontlist
;
6430 child
->font
= alloc_font();
6431 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6432 if(!child
->font
->ft_face
)
6434 free_font(child
->font
);
6439 child
->font
->font_desc
= font
->font_desc
;
6440 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6441 child
->font
->orientation
= font
->orientation
;
6442 child
->font
->scale_y
= font
->scale_y
;
6443 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6444 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6445 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6446 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6447 child
->font
->base_font
= font
;
6448 list_add_head(&child_font_list
, &child
->font
->entry
);
6449 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6453 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6456 CHILD_FONT
*child_font
;
6459 font
= font
->base_font
;
6461 *linked_font
= font
;
6463 if((*glyph
= get_glyph_index(font
, c
)))
6465 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6469 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6471 if(!child_font
->font
)
6472 if(!load_child_font(font
, child_font
))
6475 if(!child_font
->font
->ft_face
)
6477 g
= get_glyph_index(child_font
->font
, c
);
6478 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6482 *linked_font
= child_font
->font
;
6489 /*************************************************************
6490 * freetype_GetCharWidth
6492 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6494 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6497 FT_UInt glyph_index
;
6498 GdiFont
*linked_font
;
6499 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6503 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6504 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6507 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6510 EnterCriticalSection( &freetype_cs
);
6511 for(c
= firstChar
; c
<= lastChar
; c
++) {
6512 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6513 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6514 &gm
, 0, NULL
, &identity
);
6515 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6517 LeaveCriticalSection( &freetype_cs
);
6521 /*************************************************************
6522 * freetype_GetCharABCWidths
6524 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6526 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6529 FT_UInt glyph_index
;
6530 GdiFont
*linked_font
;
6531 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6535 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6536 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6539 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6542 EnterCriticalSection( &freetype_cs
);
6544 for(c
= firstChar
; c
<= lastChar
; c
++) {
6545 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6546 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6547 &gm
, 0, NULL
, &identity
);
6548 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6549 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6550 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6551 FONT_GM(linked_font
,glyph_index
)->bbx
;
6553 LeaveCriticalSection( &freetype_cs
);
6557 /*************************************************************
6558 * freetype_GetCharABCWidthsI
6560 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6562 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6565 FT_UInt glyph_index
;
6566 GdiFont
*linked_font
;
6567 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6571 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6572 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6575 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6579 EnterCriticalSection( &freetype_cs
);
6581 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6583 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6584 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6585 &gm
, 0, NULL
, &identity
);
6586 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6587 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6588 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6589 - FONT_GM(linked_font
,c
)->bbx
;
6592 for(c
= 0; c
< count
; c
++) {
6593 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6594 &gm
, 0, NULL
, &identity
);
6595 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6596 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6597 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6598 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6601 LeaveCriticalSection( &freetype_cs
);
6605 /*************************************************************
6606 * freetype_GetTextExtentExPoint
6608 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6609 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6611 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6616 FT_UInt glyph_index
;
6617 GdiFont
*linked_font
;
6618 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6622 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6623 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6626 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6629 EnterCriticalSection( &freetype_cs
);
6632 get_text_metrics( physdev
->font
, &tm
);
6633 size
->cy
= tm
.tmHeight
;
6635 for(idx
= 0; idx
< count
; idx
++) {
6636 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6637 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6638 &gm
, 0, NULL
, &identity
);
6639 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6641 if (! pnfit
|| ext
<= max_ext
) {
6651 LeaveCriticalSection( &freetype_cs
);
6652 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6656 /*************************************************************
6657 * freetype_GetTextExtentExPointI
6659 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6660 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6662 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6667 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6671 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6672 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6675 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6678 EnterCriticalSection( &freetype_cs
);
6681 get_text_metrics(physdev
->font
, &tm
);
6682 size
->cy
= tm
.tmHeight
;
6684 for(idx
= 0; idx
< count
; idx
++) {
6685 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6686 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6688 if (! pnfit
|| ext
<= max_ext
) {
6698 LeaveCriticalSection( &freetype_cs
);
6699 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6703 /*************************************************************
6704 * freetype_GetFontData
6706 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6708 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6712 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6713 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6716 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6717 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6718 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6720 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6723 /*************************************************************
6724 * freetype_GetTextFace
6726 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6729 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6733 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6734 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6737 n
= strlenW(physdev
->font
->name
) + 1;
6740 lstrcpynW(str
, physdev
->font
->name
, count
);
6746 /*************************************************************
6747 * freetype_GetTextCharsetInfo
6749 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6751 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6755 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6756 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6758 if (fs
) *fs
= physdev
->font
->fs
;
6759 return physdev
->font
->charset
;
6762 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6764 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6765 struct list
*first_hfont
;
6769 EnterCriticalSection( &freetype_cs
);
6770 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6771 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6772 if(font
== linked_font
)
6773 *new_hfont
= dc
->hFont
;
6776 first_hfont
= list_head(&linked_font
->hfontlist
);
6777 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6779 LeaveCriticalSection( &freetype_cs
);
6783 /* Retrieve a list of supported Unicode ranges for a given font.
6784 * Can be called with NULL gs to calculate the buffer size. Returns
6785 * the number of ranges found.
6787 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6789 DWORD num_ranges
= 0;
6791 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6794 FT_ULong char_code
, char_code_prev
;
6797 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6799 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6800 face
->num_glyphs
, glyph_code
, char_code
);
6802 if (!glyph_code
) return 0;
6806 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6807 gs
->ranges
[0].cGlyphs
= 0;
6808 gs
->cGlyphsSupported
= 0;
6814 if (char_code
< char_code_prev
)
6816 ERR("expected increasing char code from FT_Get_Next_Char\n");
6819 if (char_code
- char_code_prev
> 1)
6824 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6825 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6826 gs
->cGlyphsSupported
++;
6831 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6832 gs
->cGlyphsSupported
++;
6834 char_code_prev
= char_code
;
6835 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6839 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6844 /*************************************************************
6845 * freetype_GetFontUnicodeRanges
6847 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6849 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6850 DWORD size
, num_ranges
;
6854 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6855 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6858 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6859 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6862 glyphset
->cbThis
= size
;
6863 glyphset
->cRanges
= num_ranges
;
6864 glyphset
->flAccel
= 0;
6869 /*************************************************************
6870 * freetype_FontIsLinked
6872 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6874 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6879 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6880 return dev
->funcs
->pFontIsLinked( dev
);
6884 EnterCriticalSection( &freetype_cs
);
6885 ret
= !list_empty(&physdev
->font
->child_fonts
);
6886 LeaveCriticalSection( &freetype_cs
);
6890 static BOOL
is_hinting_enabled(void)
6892 /* Use the >= 2.2.0 function if available */
6893 if(pFT_Get_TrueType_Engine_Type
)
6895 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6896 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6898 #ifdef FT_DRIVER_HAS_HINTER
6903 /* otherwise if we've been compiled with < 2.2.0 headers
6904 use the internal macro */
6905 mod
= pFT_Get_Module(library
, "truetype");
6906 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6914 static BOOL
is_subpixel_rendering_enabled( void )
6916 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6917 return pFT_Library_SetLcdFilter
&&
6918 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6924 /*************************************************************************
6925 * GetRasterizerCaps (GDI32.@)
6927 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6929 static int hinting
= -1;
6930 static int subpixel
= -1;
6934 hinting
= is_hinting_enabled();
6935 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6938 if ( subpixel
== -1 )
6940 subpixel
= is_subpixel_rendering_enabled();
6941 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6944 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6945 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6947 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6948 lprs
->nLanguageID
= 0;
6952 /*************************************************************
6953 * freetype_GdiRealizationInfo
6955 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
6957 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6958 realization_info_t
*info
= ptr
;
6962 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
6963 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
6966 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
6969 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
6972 info
->cache_num
= physdev
->font
->cache_num
;
6973 info
->unknown2
= -1;
6977 /*************************************************************************
6978 * Kerning support for TrueType fonts
6980 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6982 struct TT_kern_table
6988 struct TT_kern_subtable
6997 USHORT horizontal
: 1;
6999 USHORT cross_stream
: 1;
7000 USHORT override
: 1;
7001 USHORT reserved1
: 4;
7007 struct TT_format0_kern_subtable
7011 USHORT entrySelector
;
7022 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7023 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7024 const USHORT
*glyph_to_char
,
7025 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7028 const struct TT_kern_pair
*tt_kern_pair
;
7030 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7032 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7034 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7035 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7036 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7038 if (!kern_pair
|| !cPairs
)
7041 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7043 nPairs
= min(nPairs
, cPairs
);
7045 for (i
= 0; i
< nPairs
; i
++)
7047 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7048 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7049 /* this algorithm appears to better match what Windows does */
7050 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7051 if (kern_pair
->iKernAmount
< 0)
7053 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7054 kern_pair
->iKernAmount
-= font
->ppem
;
7056 else if (kern_pair
->iKernAmount
> 0)
7058 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7059 kern_pair
->iKernAmount
+= font
->ppem
;
7061 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7063 TRACE("left %u right %u value %d\n",
7064 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7068 TRACE("copied %u entries\n", nPairs
);
7072 /*************************************************************
7073 * freetype_GetKerningPairs
7075 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7079 const struct TT_kern_table
*tt_kern_table
;
7080 const struct TT_kern_subtable
*tt_kern_subtable
;
7082 USHORT
*glyph_to_char
;
7084 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7086 if (!(font
= physdev
->font
))
7088 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7089 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7093 EnterCriticalSection( &freetype_cs
);
7094 if (font
->total_kern_pairs
!= (DWORD
)-1)
7096 if (cPairs
&& kern_pair
)
7098 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7099 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7101 else cPairs
= font
->total_kern_pairs
;
7103 LeaveCriticalSection( &freetype_cs
);
7107 font
->total_kern_pairs
= 0;
7109 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7111 if (length
== GDI_ERROR
)
7113 TRACE("no kerning data in the font\n");
7114 LeaveCriticalSection( &freetype_cs
);
7118 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7121 WARN("Out of memory\n");
7122 LeaveCriticalSection( &freetype_cs
);
7126 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7128 /* build a glyph index to char code map */
7129 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7132 WARN("Out of memory allocating a glyph index to char code map\n");
7133 HeapFree(GetProcessHeap(), 0, buf
);
7134 LeaveCriticalSection( &freetype_cs
);
7138 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7144 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7146 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7147 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7151 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7153 /* FIXME: This doesn't match what Windows does: it does some fancy
7154 * things with duplicate glyph index to char code mappings, while
7155 * we just avoid overriding existing entries.
7157 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7158 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7160 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7167 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7168 for (n
= 0; n
<= 65535; n
++)
7169 glyph_to_char
[n
] = (USHORT
)n
;
7172 tt_kern_table
= buf
;
7173 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7174 TRACE("version %u, nTables %u\n",
7175 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7177 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7179 for (i
= 0; i
< nTables
; i
++)
7181 struct TT_kern_subtable tt_kern_subtable_copy
;
7183 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7184 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7185 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7187 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7188 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7189 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7191 /* According to the TrueType specification this is the only format
7192 * that will be properly interpreted by Windows and OS/2
7194 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7196 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7198 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7199 glyph_to_char
, NULL
, 0);
7200 font
->total_kern_pairs
+= new_chunk
;
7202 if (!font
->kern_pairs
)
7203 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7204 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7206 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7207 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7209 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7210 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7213 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7215 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7218 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7219 HeapFree(GetProcessHeap(), 0, buf
);
7221 if (cPairs
&& kern_pair
)
7223 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7224 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7226 else cPairs
= font
->total_kern_pairs
;
7228 LeaveCriticalSection( &freetype_cs
);
7232 static const struct gdi_dc_funcs freetype_funcs
=
7234 NULL
, /* pAbortDoc */
7235 NULL
, /* pAbortPath */
7236 NULL
, /* pAlphaBlend */
7237 NULL
, /* pAngleArc */
7240 NULL
, /* pBeginPath */
7241 NULL
, /* pBlendImage */
7242 NULL
, /* pChoosePixelFormat */
7244 NULL
, /* pCloseFigure */
7245 NULL
, /* pCopyBitmap */
7246 NULL
, /* pCreateBitmap */
7247 NULL
, /* pCreateCompatibleDC */
7248 freetype_CreateDC
, /* pCreateDC */
7249 NULL
, /* pDeleteBitmap */
7250 freetype_DeleteDC
, /* pDeleteDC */
7251 NULL
, /* pDeleteObject */
7252 NULL
, /* pDescribePixelFormat */
7253 NULL
, /* pDeviceCapabilities */
7254 NULL
, /* pEllipse */
7256 NULL
, /* pEndPage */
7257 NULL
, /* pEndPath */
7258 freetype_EnumFonts
, /* pEnumFonts */
7259 NULL
, /* pEnumICMProfiles */
7260 NULL
, /* pExcludeClipRect */
7261 NULL
, /* pExtDeviceMode */
7262 NULL
, /* pExtEscape */
7263 NULL
, /* pExtFloodFill */
7264 NULL
, /* pExtSelectClipRgn */
7265 NULL
, /* pExtTextOut */
7266 NULL
, /* pFillPath */
7267 NULL
, /* pFillRgn */
7268 NULL
, /* pFlattenPath */
7269 freetype_FontIsLinked
, /* pFontIsLinked */
7270 NULL
, /* pFrameRgn */
7271 NULL
, /* pGdiComment */
7272 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7273 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7274 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7275 freetype_GetCharWidth
, /* pGetCharWidth */
7276 NULL
, /* pGetDeviceCaps */
7277 NULL
, /* pGetDeviceGammaRamp */
7278 freetype_GetFontData
, /* pGetFontData */
7279 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7280 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7281 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7282 NULL
, /* pGetICMProfile */
7283 NULL
, /* pGetImage */
7284 freetype_GetKerningPairs
, /* pGetKerningPairs */
7285 NULL
, /* pGetNearestColor */
7286 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7287 NULL
, /* pGetPixel */
7288 NULL
, /* pGetPixelFormat */
7289 NULL
, /* pGetSystemPaletteEntries */
7290 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7291 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7292 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7293 freetype_GetTextFace
, /* pGetTextFace */
7294 freetype_GetTextMetrics
, /* pGetTextMetrics */
7295 NULL
, /* pGradientFill */
7296 NULL
, /* pIntersectClipRect */
7297 NULL
, /* pInvertRgn */
7299 NULL
, /* pModifyWorldTransform */
7301 NULL
, /* pOffsetClipRgn */
7302 NULL
, /* pOffsetViewportOrg */
7303 NULL
, /* pOffsetWindowOrg */
7304 NULL
, /* pPaintRgn */
7307 NULL
, /* pPolyBezier */
7308 NULL
, /* pPolyBezierTo */
7309 NULL
, /* pPolyDraw */
7310 NULL
, /* pPolyPolygon */
7311 NULL
, /* pPolyPolyline */
7312 NULL
, /* pPolygon */
7313 NULL
, /* pPolyline */
7314 NULL
, /* pPolylineTo */
7315 NULL
, /* pPutImage */
7316 NULL
, /* pRealizeDefaultPalette */
7317 NULL
, /* pRealizePalette */
7318 NULL
, /* pRectangle */
7319 NULL
, /* pResetDC */
7320 NULL
, /* pRestoreDC */
7321 NULL
, /* pRoundRect */
7323 NULL
, /* pScaleViewportExt */
7324 NULL
, /* pScaleWindowExt */
7325 NULL
, /* pSelectBitmap */
7326 NULL
, /* pSelectBrush */
7327 NULL
, /* pSelectClipPath */
7328 freetype_SelectFont
, /* pSelectFont */
7329 NULL
, /* pSelectPalette */
7330 NULL
, /* pSelectPen */
7331 NULL
, /* pSetArcDirection */
7332 NULL
, /* pSetBkColor */
7333 NULL
, /* pSetBkMode */
7334 NULL
, /* pSetDCBrushColor */
7335 NULL
, /* pSetDCPenColor */
7336 NULL
, /* pSetDIBColorTable */
7337 NULL
, /* pSetDIBitsToDevice */
7338 NULL
, /* pSetDeviceClipping */
7339 NULL
, /* pSetDeviceGammaRamp */
7340 NULL
, /* pSetLayout */
7341 NULL
, /* pSetMapMode */
7342 NULL
, /* pSetMapperFlags */
7343 NULL
, /* pSetPixel */
7344 NULL
, /* pSetPixelFormat */
7345 NULL
, /* pSetPolyFillMode */
7346 NULL
, /* pSetROP2 */
7347 NULL
, /* pSetRelAbs */
7348 NULL
, /* pSetStretchBltMode */
7349 NULL
, /* pSetTextAlign */
7350 NULL
, /* pSetTextCharacterExtra */
7351 NULL
, /* pSetTextColor */
7352 NULL
, /* pSetTextJustification */
7353 NULL
, /* pSetViewportExt */
7354 NULL
, /* pSetViewportOrg */
7355 NULL
, /* pSetWindowExt */
7356 NULL
, /* pSetWindowOrg */
7357 NULL
, /* pSetWorldTransform */
7358 NULL
, /* pStartDoc */
7359 NULL
, /* pStartPage */
7360 NULL
, /* pStretchBlt */
7361 NULL
, /* pStretchDIBits */
7362 NULL
, /* pStrokeAndFillPath */
7363 NULL
, /* pStrokePath */
7364 NULL
, /* pSwapBuffers */
7365 NULL
, /* pUnrealizePalette */
7366 NULL
, /* pWidenPath */
7367 /* OpenGL not supported */
7370 #else /* HAVE_FREETYPE */
7372 /*************************************************************************/
7374 BOOL
WineEngInit(void)
7378 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7383 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7385 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7389 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7391 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7395 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7397 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7401 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7406 /*************************************************************************
7407 * GetRasterizerCaps (GDI32.@)
7409 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7411 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7413 lprs
->nLanguageID
= 0;
7417 #endif /* HAVE_FREETYPE */