2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font
);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType
;
144 static FT_Library library
= 0;
151 static FT_Version_t FT_Version
;
152 static DWORD FT_SimpleVersion
;
154 static void *ft_handle
= NULL
;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face
);
158 MAKE_FUNCPTR(FT_Get_Char_Index
);
159 MAKE_FUNCPTR(FT_Get_First_Char
);
160 MAKE_FUNCPTR(FT_Get_Module
);
161 MAKE_FUNCPTR(FT_Get_Next_Char
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
166 MAKE_FUNCPTR(FT_Init_FreeType
);
167 MAKE_FUNCPTR(FT_Library_Version
);
168 MAKE_FUNCPTR(FT_Load_Glyph
);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
170 MAKE_FUNCPTR(FT_Matrix_Multiply
);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix
);
176 MAKE_FUNCPTR(FT_New_Face
);
177 MAKE_FUNCPTR(FT_New_Memory_Face
);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
179 MAKE_FUNCPTR(FT_Outline_Transform
);
180 MAKE_FUNCPTR(FT_Outline_Translate
);
181 MAKE_FUNCPTR(FT_Render_Glyph
);
182 MAKE_FUNCPTR(FT_Select_Charmap
);
183 MAKE_FUNCPTR(FT_Set_Charmap
);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
185 MAKE_FUNCPTR(FT_Vector_Transform
);
186 MAKE_FUNCPTR(FT_Vector_Unit
);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent
);
195 MAKE_FUNCPTR(FcFontList
);
196 MAKE_FUNCPTR(FcFontSetDestroy
);
197 MAKE_FUNCPTR(FcInit
);
198 MAKE_FUNCPTR(FcObjectSetAdd
);
199 MAKE_FUNCPTR(FcObjectSetCreate
);
200 MAKE_FUNCPTR(FcObjectSetDestroy
);
201 MAKE_FUNCPTR(FcPatternCreate
);
202 MAKE_FUNCPTR(FcPatternDestroy
);
203 MAKE_FUNCPTR(FcPatternGetBool
);
204 MAKE_FUNCPTR(FcPatternGetString
);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading
;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height
, width
;
249 FT_Pos size
, x_ppem
, y_ppem
;
255 NEWTEXTMETRICEXW ntm
;
259 typedef struct tagFace
{
265 DWORD font_data_size
;
269 FT_Fixed font_version
;
272 Bitmap_Size size
; /* set if face is a bitmap */
273 BOOL external
; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily
*family
;
275 /* Cached data for Enum */
276 struct enum_data
*cached_enum_data
;
279 typedef struct tagFamily
{
281 const WCHAR
*FamilyName
;
282 const WCHAR
*EnglishName
;
284 struct list
*replacement
;
289 INT adv
; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST
{
322 struct list hfontlist
;
323 OUTLINETEXTMETRICW
*potm
;
324 DWORD total_kern_pairs
;
325 KERNINGPAIR
*kern_pairs
;
326 struct list child_fonts
;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping
*mapping
;
353 const WCHAR
*font_name
;
358 struct enum_charset_element
{
361 WCHAR name
[LF_FACESIZE
];
364 struct enum_charset_list
{
366 struct enum_charset_element element
[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
373 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list
= LIST_INIT(child_font_list
);
376 static struct list system_links
= LIST_INIT(system_links
);
378 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
380 static struct list font_list
= LIST_INIT(font_list
);
382 struct freetype_physdev
384 struct gdi_physdev dev
;
388 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
390 return (struct freetype_physdev
*)dev
;
393 static const struct gdi_dc_funcs freetype_funcs
;
395 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR
* const SystemFontValues
[] = {
422 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial
[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR
*default_serif_list
[] =
450 bitstream_vera_serif
,
454 static const WCHAR
*default_fixed_list
[] =
458 bitstream_vera_sans_mono
,
462 static const WCHAR
*default_sans_list
[] =
475 typedef struct tagFontSubst
{
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value
[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value
[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value
[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 static struct list mappings_list
= LIST_INIT( mappings_list
);
513 static CRITICAL_SECTION freetype_cs
;
514 static CRITICAL_SECTION_DEBUG critsect_debug
=
517 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
518 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback
= FALSE
;
527 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
528 static BOOL
get_outline_text_metrics(GdiFont
*font
);
529 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
531 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
547 * FIXEDFON.FON FixedSys
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
589 GSUB_ScriptRecord ScriptRecord
[1];
595 } GSUB_LangSysRecord
;
600 GSUB_LangSysRecord LangSysRecord
[1];
604 WORD LookupOrder
; /* Reserved */
605 WORD ReqFeatureIndex
;
607 WORD FeatureIndex
[1];
613 } GSUB_FeatureRecord
;
617 GSUB_FeatureRecord FeatureRecord
[1];
621 WORD FeatureParams
; /* Reserved */
623 WORD LookupListIndex
[1];
642 } GSUB_CoverageFormat1
;
647 WORD StartCoverageIndex
;
653 GSUB_RangeRecord RangeRecord
[1];
654 } GSUB_CoverageFormat2
;
657 WORD SubstFormat
; /* = 1 */
660 } GSUB_SingleSubstFormat1
;
663 WORD SubstFormat
; /* = 2 */
667 }GSUB_SingleSubstFormat2
;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
674 static char cached_path
[MAX_PATH
];
675 static const char *wine
= "/Wine", *fonts
= "/Fonts";
677 if(*cached_path
) return cached_path
;
679 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
682 WARN("can't create cached data folder\n");
685 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
688 WARN("can't create cached data path\n");
692 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
694 ERR("Could not create full path\n");
698 strcat(cached_path
, wine
);
700 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
702 WARN("Couldn't mkdir %s\n", cached_path
);
706 strcat(cached_path
, fonts
);
707 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
709 WARN("Couldn't mkdir %s\n", cached_path
);
716 /******************************************************************
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path
)
734 const char *filename
;
738 unsigned int size
, max_size
;
741 TRACE("path %s\n", path
);
743 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
746 WARN("failed to get ref\n");
750 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
757 TRACE("unable to open resource fork\n");
764 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
767 CloseResFile(res_ref
);
771 out_dir
= find_cache_dir();
773 filename
= strrchr(path
, '/');
774 if(!filename
) filename
= path
;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
785 unsigned short *num_faces_ptr
, num_faces
, face
;
788 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
790 fond
= Get1IndResource(fond_res
, idx
);
792 TRACE("got fond resource %d\n", idx
);
795 fam_rec
= *(FamRec
**)fond
;
796 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
797 num_faces
= GET_BE_WORD(*num_faces_ptr
);
799 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
800 TRACE("num faces %04x\n", num_faces
);
801 for(face
= 0; face
< num_faces
; face
++, assoc
++)
804 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
805 unsigned short size
, font_id
;
808 size
= GET_BE_WORD(assoc
->fontSize
);
809 font_id
= GET_BE_WORD(assoc
->fontID
);
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
816 TRACE("trying to load sfnt id %04x\n", font_id
);
817 sfnt
= GetResource(sfnt_res
, font_id
);
820 TRACE("can't get sfnt resource %04x\n", font_id
);
824 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
829 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
831 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
832 if(fd
!= -1 || errno
== EEXIST
)
836 unsigned char *sfnt_data
;
839 sfnt_data
= *(unsigned char**)sfnt
;
840 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
844 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
847 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
849 ret
.array
[ret
.size
++] = output
;
853 WARN("unable to create %s\n", output
);
854 HeapFree(GetProcessHeap(), 0, output
);
857 ReleaseResource(sfnt
);
860 ReleaseResource(fond
);
863 CloseResFile(res_ref
);
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL
is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed
FT_FixedFromFloat(double f
)
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
889 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
893 static const struct list
*get_face_list_from_family(const Family
*family
)
895 if (!list_empty(&family
->faces
))
896 return &family
->faces
;
898 return family
->replacement
;
901 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
906 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
907 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
909 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
912 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
914 const struct list
*face_list
;
915 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
917 face_list
= get_face_list_from_family(family
);
918 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
922 file
= strrchr(face
->file
, '/');
927 if(!strcasecmp(file
, file_nameA
))
929 HeapFree(GetProcessHeap(), 0, file_nameA
);
934 HeapFree(GetProcessHeap(), 0, file_nameA
);
938 static Family
*find_family_from_name(const WCHAR
*name
)
942 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
944 if(!strcmpiW(family
->FamilyName
, name
))
951 static Family
*find_family_from_any_name(const WCHAR
*name
)
955 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
957 if(!strcmpiW(family
->FamilyName
, name
))
959 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
966 static void DumpSubstList(void)
970 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
972 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
974 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
976 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
977 debugstr_w(psub
->to
.name
));
982 static LPWSTR
strdupW(LPCWSTR p
)
985 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
986 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
991 static LPSTR
strdupA(LPCSTR p
)
994 DWORD len
= (strlen(p
) + 1);
995 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1000 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1005 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1007 if(!strcmpiW(element
->from
.name
, from_name
) &&
1008 (element
->from
.charset
== from_charset
||
1009 element
->from
.charset
== -1))
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1020 FontSubst
*from_exist
, *to_exist
;
1022 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1024 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1026 list_remove(&from_exist
->entry
);
1027 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
1028 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
1029 HeapFree(GetProcessHeap(), 0, from_exist
);
1035 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1039 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1040 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1043 list_add_tail(subst_list
, &subst
->entry
);
1048 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1049 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1050 HeapFree(GetProcessHeap(), 0, subst
);
1054 static WCHAR
*towstr(UINT cp
, const char *str
)
1059 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1060 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1061 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1065 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1067 CHAR
*p
= strrchr(str
, ',');
1071 nc
->charset
= strtol(p
+1, NULL
, 10);
1074 nc
->name
= towstr(CP_ACP
, str
);
1077 static void LoadSubstList(void)
1081 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey
) == ERROR_SUCCESS
) {
1089 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1090 &valuelen
, &datalen
, NULL
, NULL
);
1092 valuelen
++; /* returned value doesn't include room for '\0' */
1093 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1094 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1098 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1099 &dlen
) == ERROR_SUCCESS
) {
1100 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1102 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1103 split_subst_info(&psub
->from
, value
);
1104 split_subst_info(&psub
->to
, data
);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1109 psub
->to
.charset
== DEFAULT_CHARSET
) {
1110 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1111 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1112 HeapFree(GetProcessHeap(), 0, psub
);
1114 add_font_subst(&font_subst_list
, psub
, 0);
1116 /* reset dlen and vlen */
1120 HeapFree(GetProcessHeap(), 0, data
);
1121 HeapFree(GetProcessHeap(), 0, value
);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1138 FT_UInt num_names
, name_index
;
1140 if(FT_IS_SFNT(ft_face
))
1142 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1144 for(name_index
= 0; name_index
< num_names
; name_index
++)
1146 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1148 if((name
.platform_id
== req
->platform_id
) &&
1149 (name
.encoding_id
== req
->encoding_id
) &&
1150 (name
.language_id
== req
->language_id
) &&
1151 (name
.name_id
== req
->name_id
))
1153 req
->string
= name
.string
;
1154 req
->string_len
= name
.string_len
;
1161 req
->string_len
= 0;
1165 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1170 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1171 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1172 name
.language_id
= language_id
;
1173 name
.name_id
= name_id
;
1175 if(get_name_table_entry(ft_face
, &name
))
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1181 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1183 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1184 ret
[i
] = GET_BE_WORD(*tmp
);
1187 TRACE("Got localised name %s\n", debugstr_w(ret
));
1193 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1196 LONG r
= RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, &needed
);
1197 if(r
!= ERROR_SUCCESS
) return r
;
1198 if(type
!= REG_DWORD
|| needed
!= sizeof(DWORD
)) return ERROR_BAD_CONFIGURATION
;
1199 return RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &needed
);
1202 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1204 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1207 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
)
1210 DWORD num_strikes
, max_strike_key_len
;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1218 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1219 face
->cached_enum_data
= NULL
;
1221 face
->file
= HeapAlloc(GetProcessHeap(), 0, needed
);
1222 RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, (BYTE
*)face
->file
, &needed
);
1224 face
->StyleName
= strdupW(face_name
);
1225 face
->family
= family
;
1226 face
->vertical
= (family
->FamilyName
[0] == '@');
1228 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1230 WCHAR
*fullName
= HeapAlloc(GetProcessHeap(), 0, needed
);
1231 RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, (BYTE
*)fullName
, &needed
);
1232 face
->FullName
= fullName
;
1235 face
->FullName
= NULL
;
1237 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1238 reg_load_dword(hkey_face
, face_italic_value
, &italic
);
1239 reg_load_dword(hkey_face
, face_bold_value
, &bold
);
1240 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1241 reg_load_dword(hkey_face
, face_external_value
, (DWORD
*)&face
->external
);
1243 needed
= sizeof(face
->fs
);
1244 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1246 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1248 face
->scalable
= TRUE
;
1249 memset(&face
->size
, 0, sizeof(face
->size
));
1253 face
->scalable
= FALSE
;
1254 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1255 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1256 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1257 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1258 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1262 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1266 if (italic
) face
->ntmFlags
|= NTM_ITALIC
;
1267 if (bold
) face
->ntmFlags
|= NTM_BOLD
;
1268 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1272 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1273 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1275 if(!italic
&& !bold
)
1276 list_add_head(&family
->faces
, &face
->entry
);
1278 list_add_tail(&family
->faces
, &face
->entry
);
1280 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face
, NULL
, NULL
, NULL
, &num_strikes
, &max_strike_key_len
, NULL
, NULL
,
1285 NULL
, NULL
, NULL
, NULL
);
1286 if(num_strikes
!= 0)
1288 WCHAR strike_name
[10];
1289 DWORD strike_index
= 0;
1291 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1292 while(RegEnumKeyExW(hkey_face
, strike_index
++, strike_name
, &needed
,
1293 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1296 RegOpenKeyExW(hkey_face
, strike_name
, 0, KEY_ALL_ACCESS
, &hkey_strike
);
1297 load_face(hkey_strike
, face_name
, family
);
1298 RegCloseKey(hkey_strike
);
1299 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1306 DWORD max_family_key_len
, size
;
1308 DWORD family_index
= 0;
1312 RegQueryInfoKeyW(hkey_font_cache
, NULL
, NULL
, NULL
, NULL
, &max_family_key_len
, NULL
, NULL
,
1313 NULL
, NULL
, NULL
, NULL
);
1314 family_name
= HeapAlloc(GetProcessHeap(), 0, (max_family_key_len
+ 1) * sizeof(WCHAR
));
1316 size
= max_family_key_len
+ 1;
1317 while(RegEnumKeyExW(hkey_font_cache
, family_index
++, family_name
, &size
,
1318 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1320 WCHAR
*english_family
= NULL
;
1321 DWORD face_index
= 0;
1323 DWORD max_face_key_len
;
1325 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1326 TRACE("opened family key %s\n", debugstr_w(family_name
));
1327 if(RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, NULL
, &size
) == ERROR_SUCCESS
)
1329 english_family
= HeapAlloc(GetProcessHeap(), 0, size
);
1330 RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)english_family
, &size
);
1333 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1334 family
->FamilyName
= strdupW(family_name
);
1335 family
->EnglishName
= english_family
;
1336 list_init(&family
->faces
);
1337 family
->replacement
= &family
->faces
;
1338 list_add_tail(&font_list
, &family
->entry
);
1342 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1343 subst
->from
.name
= strdupW(english_family
);
1344 subst
->from
.charset
= -1;
1345 subst
->to
.name
= strdupW(family_name
);
1346 subst
->to
.charset
= -1;
1347 add_font_subst(&font_subst_list
, subst
, 0);
1350 RegQueryInfoKeyW(hkey_family
, NULL
, NULL
, NULL
, NULL
, &max_face_key_len
, NULL
, NULL
,
1351 NULL
, NULL
, NULL
, NULL
);
1353 face_name
= HeapAlloc(GetProcessHeap(), 0, (max_face_key_len
+ 1) * sizeof(WCHAR
));
1354 size
= max_face_key_len
+ 1;
1355 while(RegEnumKeyExW(hkey_family
, face_index
++, face_name
, &size
,
1356 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1360 RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
);
1361 load_face(hkey_face
, face_name
, family
);
1362 RegCloseKey(hkey_face
);
1363 size
= max_face_key_len
+ 1;
1365 HeapFree(GetProcessHeap(), 0, face_name
);
1366 RegCloseKey(hkey_family
);
1367 size
= max_family_key_len
+ 1;
1370 HeapFree(GetProcessHeap(), 0, family_name
);
1373 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1376 HKEY hkey_wine_fonts
;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1380 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1381 if(ret
!= ERROR_SUCCESS
)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1387 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1388 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1389 RegCloseKey(hkey_wine_fonts
);
1393 static void add_face_to_cache(Face
*face
)
1395 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1396 WCHAR
*face_key_name
;
1398 create_font_cache_key(&hkey_font_cache
, NULL
);
1400 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1401 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1402 if(face
->family
->EnglishName
)
1403 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1404 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1407 face_key_name
= face
->StyleName
;
1410 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1411 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1412 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1414 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1417 HeapFree(GetProcessHeap(), 0, face_key_name
);
1419 RegSetValueExA(hkey_face
, "File Name", 0, REG_BINARY
, (BYTE
*)face
->file
, strlen(face
->file
) + 1);
1421 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1422 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1424 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1425 reg_save_dword(hkey_face
, face_italic_value
, (face
->ntmFlags
& NTM_ITALIC
) != 0);
1426 reg_save_dword(hkey_face
, face_bold_value
, (face
->ntmFlags
& NTM_BOLD
) != 0);
1427 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1428 reg_save_dword(hkey_face
, face_external_value
, face
->external
);
1430 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1434 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1435 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1436 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1437 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1438 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1439 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1441 RegCloseKey(hkey_face
);
1442 RegCloseKey(hkey_family
);
1443 RegCloseKey(hkey_font_cache
);
1446 static inline int TestStyles(DWORD flags
, DWORD styles
)
1448 return (flags
& styles
) == styles
;
1451 static inline int style_order(Face
*face
)
1453 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1455 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1457 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1459 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face
->family
->FamilyName
),
1464 debugstr_w(face
->StyleName
),
1470 static WCHAR
*prepend_at(WCHAR
*family
)
1477 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1479 strcpyW(str
+ 1, family
);
1480 HeapFree(GetProcessHeap(), 0, family
);
1484 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1486 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1487 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1489 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID() );
1495 else if (!strcmpiW( *name
, *english
))
1497 HeapFree( GetProcessHeap(), 0, *english
);
1503 *name
= prepend_at( *name
);
1504 *english
= prepend_at( *english
);
1508 /****************************************************************
1509 * NB This function stores the ptrs to the strings to save copying.
1510 * Don't free them after calling.
1512 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1514 Family
*family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1515 family
->FamilyName
= name
;
1516 family
->EnglishName
= english_name
;
1517 list_init( &family
->faces
);
1518 family
->replacement
= &family
->faces
;
1523 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1526 WCHAR
*name
, *english_name
;
1528 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1530 family
= find_family_from_name( name
);
1534 family
= create_family( name
, english_name
);
1535 list_add_tail( &font_list
, &family
->entry
);
1539 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1540 subst
->from
.name
= strdupW( english_name
);
1541 subst
->from
.charset
= -1;
1542 subst
->to
.name
= strdupW( name
);
1543 subst
->to
.charset
= -1;
1544 add_font_subst( &font_subst_list
, subst
, 0 );
1549 HeapFree( GetProcessHeap(), 0, name
);
1550 HeapFree( GetProcessHeap(), 0, english_name
);
1556 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1558 FT_Fixed version
= 0;
1561 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1562 if (header
) version
= header
->Font_Revision
;
1567 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1570 FT_ULong table_size
= 0;
1572 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1573 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1574 if (flags
== 0) flags
= NTM_REGULAR
;
1576 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1577 flags
|= NTM_PS_OPENTYPE
;
1582 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1584 int internal_leading
= 0;
1585 FT_WinFNT_HeaderRec winfnt_header
;
1587 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1588 internal_leading
= winfnt_header
.internal_leading
;
1590 return internal_leading
;
1593 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1598 FT_WinFNT_HeaderRec winfnt_header
;
1601 memset( fs
, 0, sizeof(*fs
) );
1603 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1606 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1607 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1608 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1609 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1611 if (os2
->version
== 0)
1613 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1614 fs
->fsCsb
[0] = FS_LATIN1
;
1616 fs
->fsCsb
[0] = FS_SYMBOL
;
1620 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1621 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1626 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1628 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1629 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1630 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1635 if (fs
->fsCsb
[0] == 0)
1637 /* let's see if we can find any interesting cmaps */
1638 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1640 switch (ft_face
->charmaps
[i
]->encoding
)
1642 case FT_ENCODING_UNICODE
:
1643 case FT_ENCODING_APPLE_ROMAN
:
1644 fs
->fsCsb
[0] |= FS_LATIN1
;
1646 case FT_ENCODING_MS_SYMBOL
:
1647 fs
->fsCsb
[0] |= FS_SYMBOL
;
1656 static inline void free_face( Face
*face
)
1658 HeapFree( GetProcessHeap(), 0, face
->file
);
1659 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1660 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1661 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1662 HeapFree( GetProcessHeap(), 0, face
);
1665 #define ADDFONT_EXTERNAL_FONT 0x01
1666 #define ADDFONT_FORCE_BITMAP 0x02
1667 #define ADDFONT_ADD_TO_CACHE 0x04
1669 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1670 DWORD flags
, BOOL vertical
)
1672 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1673 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1675 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1676 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1679 face
->file
= strdupA( file
);
1680 face
->font_data_ptr
= NULL
;
1681 face
->font_data_size
= 0;
1686 face
->font_data_ptr
= font_data_ptr
;
1687 face
->font_data_size
= font_data_size
;
1690 face
->face_index
= face_index
;
1691 get_fontsig( ft_face
, &face
->fs
);
1692 face
->ntmFlags
= get_ntm_flags( ft_face
);
1693 face
->font_version
= get_font_version( ft_face
);
1695 if (FT_IS_SCALABLE( ft_face
))
1697 memset( &face
->size
, 0, sizeof(face
->size
) );
1698 face
->scalable
= TRUE
;
1702 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1703 size
->height
, size
->width
, size
->size
>> 6,
1704 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1705 face
->size
.height
= size
->height
;
1706 face
->size
.width
= size
->width
;
1707 face
->size
.size
= size
->size
;
1708 face
->size
.x_ppem
= size
->x_ppem
;
1709 face
->size
.y_ppem
= size
->y_ppem
;
1710 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1711 face
->scalable
= FALSE
;
1714 face
->vertical
= vertical
;
1715 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1716 face
->family
= NULL
;
1717 face
->cached_enum_data
= NULL
;
1719 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1720 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1721 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1722 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1727 static inline BOOL
faces_equal( Face
*f1
, Face
*f2
)
1729 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1730 if (f1
->scalable
) return TRUE
;
1731 if (f2
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1732 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1735 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1739 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1741 if (faces_equal( face
, cursor
))
1743 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1744 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1745 cursor
->font_version
, face
->font_version
);
1747 if (face
->font_version
<= cursor
->font_version
)
1749 TRACE("Original font is newer so skipping this one\n");
1754 TRACE("Replacing original with this one\n");
1755 list_add_before( &cursor
->entry
, &face
->entry
);
1756 face
->family
= family
;
1757 list_remove( &cursor
->entry
);
1758 free_face( cursor
);
1763 if (style_order( face
) < style_order( cursor
)) break;
1766 list_add_before( &cursor
->entry
, &face
->entry
);
1767 face
->family
= family
;
1771 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1772 FT_Long face_index
, DWORD flags
, BOOL vertical
)
1777 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
, vertical
);
1778 family
= get_family( ft_face
, vertical
);
1779 if (!insert_face_in_family_list( face
, family
))
1785 if (flags
& ADDFONT_ADD_TO_CACHE
)
1786 add_face_to_cache( face
);
1788 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1789 debugstr_w(face
->StyleName
));
1792 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1793 FT_Long face_index
, BOOL allow_bitmap
)
1801 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1802 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1806 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1807 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1812 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1816 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1817 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1819 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1823 if (!FT_IS_SFNT( ft_face
))
1825 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1827 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1833 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1834 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1835 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1837 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1838 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1842 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1843 we don't want to load these. */
1844 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1848 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1850 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1856 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1858 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1864 pFT_Done_Face( ft_face
);
1868 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1871 FT_Long face_index
= 0, num_faces
;
1874 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1875 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1877 #ifdef HAVE_CARBON_CARBON_H
1880 char **mac_list
= expand_mac_font(file
);
1883 BOOL had_one
= FALSE
;
1885 for(cursor
= mac_list
; *cursor
; cursor
++)
1888 AddFontToList(*cursor
, NULL
, 0, flags
);
1889 HeapFree(GetProcessHeap(), 0, *cursor
);
1891 HeapFree(GetProcessHeap(), 0, mac_list
);
1896 #endif /* HAVE_CARBON_CARBON_H */
1899 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_FORCE_BITMAP
);
1900 if (!ft_face
) return 0;
1902 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1904 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1905 pFT_Done_Face(ft_face
);
1909 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1912 if (FT_HAS_VERTICAL(ft_face
))
1914 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1918 num_faces
= ft_face
->num_faces
;
1919 pFT_Done_Face(ft_face
);
1920 } while(num_faces
> ++face_index
);
1924 static void DumpFontList(void)
1928 struct list
*family_elem_ptr
, *face_elem_ptr
;
1930 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1931 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1932 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1933 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1934 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1935 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1937 TRACE(" %d", face
->size
.height
);
1944 /***********************************************************
1945 * The replacement list is a way to map an entire font
1946 * family onto another family. For example adding
1948 * [HKCU\Software\Wine\Fonts\Replacements]
1949 * "Wingdings"="Winedings"
1951 * would enumerate the Winedings font both as Winedings and
1952 * Wingdings. However if a real Wingdings font is present the
1953 * replacement does not take place.
1956 static void LoadReplaceList(void)
1959 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1964 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1965 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1967 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1968 &valuelen
, &datalen
, NULL
, NULL
);
1970 valuelen
++; /* returned value doesn't include room for '\0' */
1971 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1972 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1976 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1977 &dlen
) == ERROR_SUCCESS
) {
1978 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1979 /* "NewName"="Oldname" */
1980 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1982 if(!find_family_from_any_name(value
))
1984 Family
* const family
= find_family_from_any_name(data
);
1987 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
1988 if (new_family
!= NULL
)
1990 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
1991 new_family
->FamilyName
= strdupW(value
);
1992 new_family
->EnglishName
= NULL
;
1993 list_init(&new_family
->faces
);
1994 new_family
->replacement
= &family
->faces
;
1995 list_add_tail(&font_list
, &new_family
->entry
);
2000 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2005 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2007 /* reset dlen and vlen */
2011 HeapFree(GetProcessHeap(), 0, data
);
2012 HeapFree(GetProcessHeap(), 0, value
);
2017 static const WCHAR
*font_links_list
[] =
2019 Lucida_Sans_Unicode
,
2020 Microsoft_Sans_Serif
,
2024 static const struct font_links_defaults_list
2026 /* Keyed off substitution for "MS Shell Dlg" */
2027 const WCHAR
*shelldlg
;
2028 /* Maximum of four substitutes, plus terminating NULL pointer */
2029 const WCHAR
*substitutes
[5];
2030 } font_links_defaults_list
[] =
2032 /* Non East-Asian */
2033 { Tahoma
, /* FIXME unverified ordering */
2034 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2036 /* Below lists are courtesy of
2037 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2041 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2043 /* Chinese Simplified */
2045 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2049 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2051 /* Chinese Traditional */
2053 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2058 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2060 SYSTEM_LINKS
*font_link
;
2062 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2064 if(!strcmpiW(font_link
->font_name
, name
))
2071 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2083 SYSTEM_LINKS
*font_link
;
2085 psub
= get_font_subst(&font_subst_list
, name
, -1);
2086 /* Don't store fonts that are only substitutes for other fonts */
2089 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2093 font_link
= find_font_link(name
);
2094 if (font_link
== NULL
)
2096 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2097 font_link
->font_name
= strdupW(name
);
2098 list_init(&font_link
->links
);
2099 list_add_tail(&system_links
, &font_link
->entry
);
2102 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2103 for (i
= 0; values
[i
] != NULL
; i
++)
2105 const struct list
*face_list
;
2106 CHILD_FONT
*child_font
;
2109 if (!strcmpiW(name
,value
))
2111 psub
= get_font_subst(&font_subst_list
, value
, -1);
2113 value
= psub
->to
.name
;
2114 family
= find_family_from_name(value
);
2118 /* Use first extant filename for this Family */
2119 face_list
= get_face_list_from_family(family
);
2120 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2124 file
= strrchr(face
->file
, '/');
2133 fileW
= towstr(CP_UNIXCP
, file
);
2135 face
= find_face_from_filename(fileW
, value
);
2138 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2142 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2143 child_font
->face
= face
;
2144 child_font
->font
= NULL
;
2145 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2146 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2147 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2148 list_add_tail(&font_link
->links
, &child_font
->entry
);
2150 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2151 HeapFree(GetProcessHeap(), 0, fileW
);
2157 /*************************************************************
2160 static BOOL
init_system_links(void)
2164 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2165 WCHAR
*value
, *data
;
2166 WCHAR
*entry
, *next
;
2167 SYSTEM_LINKS
*font_link
, *system_font_link
;
2168 CHILD_FONT
*child_font
;
2169 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2170 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2171 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2176 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2178 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2179 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2180 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2181 val_len
= max_val
+ 1;
2182 data_len
= max_data
;
2184 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2186 psub
= get_font_subst(&font_subst_list
, value
, -1);
2187 /* Don't store fonts that are only substitutes for other fonts */
2190 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2193 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2194 font_link
->font_name
= strdupW(value
);
2195 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2196 list_init(&font_link
->links
);
2197 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2200 CHILD_FONT
*child_font
;
2202 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2204 next
= entry
+ strlenW(entry
) + 1;
2206 face_name
= strchrW(entry
, ',');
2210 while(isspaceW(*face_name
))
2213 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2215 face_name
= psub
->to
.name
;
2217 face
= find_face_from_filename(entry
, face_name
);
2220 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2224 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2225 child_font
->face
= face
;
2226 child_font
->font
= NULL
;
2227 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2228 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2229 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2230 list_add_tail(&font_link
->links
, &child_font
->entry
);
2232 list_add_tail(&system_links
, &font_link
->entry
);
2234 val_len
= max_val
+ 1;
2235 data_len
= max_data
;
2238 HeapFree(GetProcessHeap(), 0, value
);
2239 HeapFree(GetProcessHeap(), 0, data
);
2244 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2246 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2250 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2252 const FontSubst
*psub2
;
2253 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2255 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2257 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2258 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2260 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2261 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2263 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2265 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2271 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2274 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2275 system_font_link
->font_name
= strdupW(System
);
2276 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2277 list_init(&system_font_link
->links
);
2279 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2282 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2283 child_font
->face
= face
;
2284 child_font
->font
= NULL
;
2285 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2286 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2287 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2288 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2290 font_link
= find_font_link(Tahoma
);
2291 if (font_link
!= NULL
)
2293 CHILD_FONT
*font_link_entry
;
2294 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2296 CHILD_FONT
*new_child
;
2297 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2298 new_child
->face
= font_link_entry
->face
;
2299 new_child
->font
= NULL
;
2300 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2301 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2302 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2305 list_add_tail(&system_links
, &system_font_link
->entry
);
2309 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2312 struct dirent
*dent
;
2313 char path
[MAX_PATH
];
2315 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2317 dir
= opendir(dirname
);
2319 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2322 while((dent
= readdir(dir
)) != NULL
) {
2323 struct stat statbuf
;
2325 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2328 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2330 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2332 if(stat(path
, &statbuf
) == -1)
2334 WARN("Can't stat %s\n", debugstr_a(path
));
2337 if(S_ISDIR(statbuf
.st_mode
))
2338 ReadFontDir(path
, external_fonts
);
2341 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2342 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2343 AddFontToList(path
, NULL
, 0, addfont_flags
);
2350 static void load_fontconfig_fonts(void)
2352 #ifdef SONAME_LIBFONTCONFIG
2353 void *fc_handle
= NULL
;
2362 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2364 TRACE("Wine cannot find the fontconfig library (%s).\n",
2365 SONAME_LIBFONTCONFIG
);
2368 #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;}
2369 LOAD_FUNCPTR(FcConfigGetCurrent
);
2370 LOAD_FUNCPTR(FcFontList
);
2371 LOAD_FUNCPTR(FcFontSetDestroy
);
2372 LOAD_FUNCPTR(FcInit
);
2373 LOAD_FUNCPTR(FcObjectSetAdd
);
2374 LOAD_FUNCPTR(FcObjectSetCreate
);
2375 LOAD_FUNCPTR(FcObjectSetDestroy
);
2376 LOAD_FUNCPTR(FcPatternCreate
);
2377 LOAD_FUNCPTR(FcPatternDestroy
);
2378 LOAD_FUNCPTR(FcPatternGetBool
);
2379 LOAD_FUNCPTR(FcPatternGetString
);
2382 if(!pFcInit()) return;
2384 config
= pFcConfigGetCurrent();
2385 pat
= pFcPatternCreate();
2386 os
= pFcObjectSetCreate();
2387 pFcObjectSetAdd(os
, FC_FILE
);
2388 pFcObjectSetAdd(os
, FC_SCALABLE
);
2389 fontset
= pFcFontList(config
, pat
, os
);
2390 if(!fontset
) return;
2391 for(i
= 0; i
< fontset
->nfont
; i
++) {
2394 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2396 TRACE("fontconfig: %s\n", file
);
2398 /* We're just interested in OT/TT fonts for now, so this hack just
2399 picks up the scalable fonts without extensions .pf[ab] to save time
2400 loading every other font */
2402 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2404 TRACE("not scalable\n");
2408 len
= strlen( file
);
2409 if(len
< 4) continue;
2410 ext
= &file
[ len
- 3 ];
2411 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2412 AddFontToList(file
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2414 pFcFontSetDestroy(fontset
);
2415 pFcObjectSetDestroy(os
);
2416 pFcPatternDestroy(pat
);
2422 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2425 const char *data_dir
= wine_get_data_dir();
2427 if (!data_dir
) data_dir
= wine_get_build_dir();
2434 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2436 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2438 strcpy(unix_name
, data_dir
);
2439 strcat(unix_name
, "/fonts/");
2441 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2443 EnterCriticalSection( &freetype_cs
);
2444 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2445 LeaveCriticalSection( &freetype_cs
);
2446 HeapFree(GetProcessHeap(), 0, unix_name
);
2451 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2453 static const WCHAR slashW
[] = {'\\','\0'};
2455 WCHAR windowsdir
[MAX_PATH
];
2458 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2459 strcatW(windowsdir
, fontsW
);
2460 strcatW(windowsdir
, slashW
);
2461 strcatW(windowsdir
, file
);
2462 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2463 EnterCriticalSection( &freetype_cs
);
2464 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2465 LeaveCriticalSection( &freetype_cs
);
2466 HeapFree(GetProcessHeap(), 0, unixname
);
2471 static void load_system_fonts(void)
2474 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2475 const WCHAR
* const *value
;
2477 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2480 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2481 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2482 strcatW(windowsdir
, fontsW
);
2483 for(value
= SystemFontValues
; *value
; value
++) {
2484 dlen
= sizeof(data
);
2485 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2489 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2490 if((unixname
= wine_get_unix_file_name(pathW
))) {
2491 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2492 HeapFree(GetProcessHeap(), 0, unixname
);
2495 load_font_from_data_dir(data
);
2502 /*************************************************************
2504 * This adds registry entries for any externally loaded fonts
2505 * (fonts from fontconfig or FontDirs). It also deletes entries
2506 * of no longer existing fonts.
2509 static void update_reg_entries(void)
2511 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2516 struct list
*family_elem_ptr
, *face_elem_ptr
;
2518 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2519 static const WCHAR spaceW
[] = {' ', '\0'};
2522 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2523 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2524 ERR("Can't create Windows font reg key\n");
2528 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2529 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2530 ERR("Can't create Windows font reg key\n");
2534 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2535 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2536 ERR("Can't create external font reg key\n");
2540 /* enumerate the fonts and add external ones to the two keys */
2542 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2543 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2544 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2545 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2546 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2547 if(!face
->external
) continue;
2549 if (!(face
->ntmFlags
& NTM_REGULAR
))
2550 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2551 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2552 strcpyW(valueW
, family
->FamilyName
);
2553 if(len
!= len_fam
) {
2554 strcatW(valueW
, spaceW
);
2555 strcatW(valueW
, face
->StyleName
);
2557 strcatW(valueW
, TrueType
);
2559 file
= wine_get_dos_file_name(face
->file
);
2561 len
= strlenW(file
) + 1;
2564 if((path
= strrchr(face
->file
, '/')) == NULL
)
2568 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2570 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2571 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2573 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2574 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2575 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2577 HeapFree(GetProcessHeap(), 0, file
);
2578 HeapFree(GetProcessHeap(), 0, valueW
);
2582 if(external_key
) RegCloseKey(external_key
);
2583 if(win9x_key
) RegCloseKey(win9x_key
);
2584 if(winnt_key
) RegCloseKey(winnt_key
);
2588 static void delete_external_font_keys(void)
2590 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2591 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2595 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2596 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2597 ERR("Can't create Windows font reg key\n");
2601 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2602 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2603 ERR("Can't create Windows font reg key\n");
2607 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2608 ERR("Can't create external font reg key\n");
2612 /* Delete all external fonts added last time */
2614 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2615 &valuelen
, &datalen
, NULL
, NULL
);
2616 valuelen
++; /* returned value doesn't include room for '\0' */
2617 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2618 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2620 dlen
= datalen
* sizeof(WCHAR
);
2623 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2624 &dlen
) == ERROR_SUCCESS
) {
2626 RegDeleteValueW(winnt_key
, valueW
);
2627 RegDeleteValueW(win9x_key
, valueW
);
2628 /* reset dlen and vlen */
2632 HeapFree(GetProcessHeap(), 0, data
);
2633 HeapFree(GetProcessHeap(), 0, valueW
);
2635 /* Delete the old external fonts key */
2636 RegCloseKey(external_key
);
2637 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2640 if(win9x_key
) RegCloseKey(win9x_key
);
2641 if(winnt_key
) RegCloseKey(winnt_key
);
2644 /*************************************************************
2645 * WineEngAddFontResourceEx
2648 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2654 if (ft_handle
) /* do it only if we have freetype up and running */
2659 FIXME("Ignoring flags %x\n", flags
);
2661 if((unixname
= wine_get_unix_file_name(file
)))
2663 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2665 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2666 EnterCriticalSection( &freetype_cs
);
2667 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2668 LeaveCriticalSection( &freetype_cs
);
2669 HeapFree(GetProcessHeap(), 0, unixname
);
2671 if (!ret
&& !strchrW(file
, '\\')) {
2672 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2673 ret
= load_font_from_winfonts_dir(file
);
2675 /* Try in datadir/fonts (or builddir/fonts),
2676 * needed for Magic the Gathering Online
2678 ret
= load_font_from_data_dir(file
);
2685 /*************************************************************
2686 * WineEngAddFontMemResourceEx
2689 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2693 if (ft_handle
) /* do it only if we have freetype up and running */
2695 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2697 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2698 memcpy(pFontCopy
, pbFont
, cbFont
);
2700 EnterCriticalSection( &freetype_cs
);
2701 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2702 LeaveCriticalSection( &freetype_cs
);
2706 TRACE("AddFontToList failed\n");
2707 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2710 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2711 * For now return something unique but quite random
2713 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2714 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2721 /*************************************************************
2722 * WineEngRemoveFontResourceEx
2725 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2728 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2732 static const struct nls_update_font_list
2734 UINT ansi_cp
, oem_cp
;
2735 const char *oem
, *fixed
, *system
;
2736 const char *courier
, *serif
, *small
, *sserif
;
2737 /* these are for font substitutes */
2738 const char *shelldlg
, *tmsrmn
;
2739 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2743 const char *from
, *to
;
2744 } arial_0
, courier_new_0
, times_new_roman_0
;
2745 } nls_update_font_list
[] =
2747 /* Latin 1 (United States) */
2748 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2749 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2750 "Tahoma","Times New Roman",
2751 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2754 /* Latin 1 (Multilingual) */
2755 { 1252, 850, "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
,
2761 /* Eastern Europe */
2762 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2763 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2764 "Tahoma","Times New Roman", /* FIXME unverified */
2765 "Fixedsys,238", "System,238",
2766 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2767 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2768 { "Arial CE,0", "Arial,238" },
2769 { "Courier New CE,0", "Courier New,238" },
2770 { "Times New Roman CE,0", "Times New Roman,238" }
2773 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2774 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2775 "Tahoma","Times New Roman", /* FIXME unverified */
2776 "Fixedsys,204", "System,204",
2777 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2778 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2779 { "Arial Cyr,0", "Arial,204" },
2780 { "Courier New Cyr,0", "Courier New,204" },
2781 { "Times New Roman Cyr,0", "Times New Roman,204" }
2784 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2785 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2786 "Tahoma","Times New Roman", /* FIXME unverified */
2787 "Fixedsys,161", "System,161",
2788 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2789 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2790 { "Arial Greek,0", "Arial,161" },
2791 { "Courier New Greek,0", "Courier New,161" },
2792 { "Times New Roman Greek,0", "Times New Roman,161" }
2795 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2796 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2797 "Tahoma","Times New Roman", /* FIXME unverified */
2798 "Fixedsys,162", "System,162",
2799 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2800 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2801 { "Arial Tur,0", "Arial,162" },
2802 { "Courier New Tur,0", "Courier New,162" },
2803 { "Times New Roman Tur,0", "Times New Roman,162" }
2806 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2807 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2808 "Tahoma","Times New Roman", /* FIXME unverified */
2809 "Fixedsys,177", "System,177",
2810 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2811 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2815 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2816 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2817 "Tahoma","Times New Roman", /* FIXME unverified */
2818 "Fixedsys,178", "System,178",
2819 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2820 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2824 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2825 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2826 "Tahoma","Times New Roman", /* FIXME unverified */
2827 "Fixedsys,186", "System,186",
2828 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2829 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2830 { "Arial Baltic,0", "Arial,186" },
2831 { "Courier New Baltic,0", "Courier New,186" },
2832 { "Times New Roman Baltic,0", "Times New Roman,186" }
2835 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2836 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2837 "Tahoma","Times New Roman", /* FIXME unverified */
2838 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2842 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2843 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2844 "Tahoma","Times New Roman", /* FIXME unverified */
2845 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2849 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2850 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2851 "MS UI Gothic","MS Serif",
2852 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2855 /* Chinese Simplified */
2856 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2857 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2858 "SimSun", "NSimSun",
2859 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2863 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2864 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2866 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2869 /* Chinese Traditional */
2870 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2871 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2872 "PMingLiU", "MingLiU",
2873 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2878 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2880 return ( ansi_cp
== 932 /* CP932 for Japanese */
2881 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2882 || ansi_cp
== 949 /* CP949 for Korean */
2883 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2886 static inline HKEY
create_fonts_NT_registry_key(void)
2890 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2891 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2895 static inline HKEY
create_fonts_9x_registry_key(void)
2899 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2900 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2904 static inline HKEY
create_config_fonts_registry_key(void)
2908 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2909 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2913 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2915 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2916 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2917 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2918 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2921 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2924 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2926 RegDeleteValueA(hkey
, name
);
2929 static void update_font_info(void)
2931 char buf
[40], cpbuf
[40];
2934 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2937 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2940 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2941 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2942 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2943 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2944 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2946 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2947 if (is_dbcs_ansi_cp(ansi_cp
))
2948 use_default_fallback
= TRUE
;
2951 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2953 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2958 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2960 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2962 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2965 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2969 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2970 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2972 hkey
= create_config_fonts_registry_key();
2973 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2974 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2975 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2978 hkey
= create_fonts_NT_registry_key();
2979 add_font_list(hkey
, &nls_update_font_list
[i
]);
2982 hkey
= create_fonts_9x_registry_key();
2983 add_font_list(hkey
, &nls_update_font_list
[i
]);
2986 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2988 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2989 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2990 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2991 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2993 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2994 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2995 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2996 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2997 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2998 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2999 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3000 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3002 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3003 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3004 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3012 /* Delete the FontSubstitutes from other locales */
3013 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3015 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3016 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3017 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3023 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3026 static BOOL
init_freetype(void)
3028 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3031 "Wine cannot find the FreeType font library. To enable Wine to\n"
3032 "use TrueType fonts please install a version of FreeType greater than\n"
3033 "or equal to 2.0.5.\n"
3034 "http://www.freetype.org\n");
3038 #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;}
3040 LOAD_FUNCPTR(FT_Done_Face
)
3041 LOAD_FUNCPTR(FT_Get_Char_Index
)
3042 LOAD_FUNCPTR(FT_Get_First_Char
)
3043 LOAD_FUNCPTR(FT_Get_Module
)
3044 LOAD_FUNCPTR(FT_Get_Next_Char
)
3045 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3046 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3047 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3048 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3049 LOAD_FUNCPTR(FT_Init_FreeType
)
3050 LOAD_FUNCPTR(FT_Library_Version
)
3051 LOAD_FUNCPTR(FT_Load_Glyph
)
3052 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3053 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3054 #ifndef FT_MULFIX_INLINED
3055 LOAD_FUNCPTR(FT_MulFix
)
3057 LOAD_FUNCPTR(FT_New_Face
)
3058 LOAD_FUNCPTR(FT_New_Memory_Face
)
3059 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3060 LOAD_FUNCPTR(FT_Outline_Transform
)
3061 LOAD_FUNCPTR(FT_Outline_Translate
)
3062 LOAD_FUNCPTR(FT_Render_Glyph
)
3063 LOAD_FUNCPTR(FT_Select_Charmap
)
3064 LOAD_FUNCPTR(FT_Set_Charmap
)
3065 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3066 LOAD_FUNCPTR(FT_Vector_Transform
)
3067 LOAD_FUNCPTR(FT_Vector_Unit
)
3069 /* Don't warn if these ones are missing */
3070 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3071 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3072 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3075 if(pFT_Init_FreeType(&library
) != 0) {
3076 ERR("Can't init FreeType library\n");
3077 wine_dlclose(ft_handle
, NULL
, 0);
3081 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3083 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3084 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3085 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3086 ((FT_Version
.patch
) & 0x0000ff);
3088 font_driver
= &freetype_funcs
;
3093 "Wine cannot find certain functions that it needs inside the FreeType\n"
3094 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3095 "FreeType to at least version 2.1.4.\n"
3096 "http://www.freetype.org\n");
3097 wine_dlclose(ft_handle
, NULL
, 0);
3102 static void init_font_list(void)
3104 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3105 static const WCHAR pathW
[] = {'P','a','t','h',0};
3107 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3108 WCHAR windowsdir
[MAX_PATH
];
3111 const char *data_dir
;
3113 delete_external_font_keys();
3115 /* load the system bitmap fonts */
3116 load_system_fonts();
3118 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3119 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3120 strcatW(windowsdir
, fontsW
);
3121 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3123 ReadFontDir(unixname
, FALSE
);
3124 HeapFree(GetProcessHeap(), 0, unixname
);
3127 /* load the system truetype fonts */
3128 data_dir
= wine_get_data_dir();
3129 if (!data_dir
) data_dir
= wine_get_build_dir();
3130 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3132 strcpy(unixname
, data_dir
);
3133 strcat(unixname
, "/fonts/");
3134 ReadFontDir(unixname
, TRUE
);
3135 HeapFree(GetProcessHeap(), 0, unixname
);
3138 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3139 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3140 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3142 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3143 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3144 &hkey
) == ERROR_SUCCESS
)
3146 LPWSTR data
, valueW
;
3147 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3148 &valuelen
, &datalen
, NULL
, NULL
);
3150 valuelen
++; /* returned value doesn't include room for '\0' */
3151 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3152 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3155 dlen
= datalen
* sizeof(WCHAR
);
3157 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3158 &dlen
) == ERROR_SUCCESS
)
3160 if(data
[0] && (data
[1] == ':'))
3162 if((unixname
= wine_get_unix_file_name(data
)))
3164 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3165 HeapFree(GetProcessHeap(), 0, unixname
);
3168 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3170 WCHAR pathW
[MAX_PATH
];
3171 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3174 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3175 if((unixname
= wine_get_unix_file_name(pathW
)))
3177 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3178 HeapFree(GetProcessHeap(), 0, unixname
);
3181 load_font_from_data_dir(data
);
3183 /* reset dlen and vlen */
3188 HeapFree(GetProcessHeap(), 0, data
);
3189 HeapFree(GetProcessHeap(), 0, valueW
);
3193 load_fontconfig_fonts();
3195 /* then look in any directories that we've specified in the config file */
3196 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3197 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3203 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3205 len
+= sizeof(WCHAR
);
3206 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3207 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3209 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3210 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3211 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3212 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3216 LPSTR next
= strchr( ptr
, ':' );
3217 if (next
) *next
++ = 0;
3218 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3219 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3221 strcpy( unixname
, home
);
3222 strcat( unixname
, ptr
+ 1 );
3223 ReadFontDir( unixname
, TRUE
);
3224 HeapFree( GetProcessHeap(), 0, unixname
);
3227 ReadFontDir( ptr
, TRUE
);
3230 HeapFree( GetProcessHeap(), 0, valueA
);
3232 HeapFree( GetProcessHeap(), 0, valueW
);
3238 /* Mac default font locations. */
3239 ReadFontDir( "/Library/Fonts", TRUE
);
3240 ReadFontDir( "/Network/Library/Fonts", TRUE
);
3241 ReadFontDir( "/System/Library/Fonts", TRUE
);
3242 if ((home
= getenv( "HOME" )))
3244 unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(home
)+15 );
3245 strcpy( unixname
, home
);
3246 strcat( unixname
, "/Library/Fonts" );
3247 ReadFontDir( unixname
, TRUE
);
3248 HeapFree( GetProcessHeap(), 0, unixname
);
3253 static BOOL
move_to_front(const WCHAR
*name
)
3255 Family
*family
, *cursor2
;
3256 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3258 if(!strcmpiW(family
->FamilyName
, name
))
3260 list_remove(&family
->entry
);
3261 list_add_head(&font_list
, &family
->entry
);
3268 static BOOL
set_default(const WCHAR
**name_list
)
3272 if (move_to_front(*name_list
)) return TRUE
;
3279 static void reorder_font_list(void)
3281 set_default( default_serif_list
);
3282 set_default( default_fixed_list
);
3283 set_default( default_sans_list
);
3286 /*************************************************************
3289 * Initialize FreeType library and create a list of available faces
3291 BOOL
WineEngInit(void)
3293 HKEY hkey_font_cache
;
3297 /* update locale dependent font info in registry */
3300 if(!init_freetype()) return FALSE
;
3302 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3304 ERR("Failed to create font mutex\n");
3307 WaitForSingleObject(font_mutex
, INFINITE
);
3309 create_font_cache_key(&hkey_font_cache
, &disposition
);
3311 if(disposition
== REG_CREATED_NEW_KEY
)
3314 load_font_list_from_cache(hkey_font_cache
);
3316 RegCloseKey(hkey_font_cache
);
3318 reorder_font_list();
3325 if(disposition
== REG_CREATED_NEW_KEY
)
3326 update_reg_entries();
3328 init_system_links();
3330 ReleaseMutex(font_mutex
);
3335 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3338 TT_HoriHeader
*pHori
;
3342 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3343 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3345 if(height
== 0) height
= 16;
3347 /* Calc. height of EM square:
3349 * For +ve lfHeight we have
3350 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3351 * Re-arranging gives:
3352 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3354 * For -ve lfHeight we have
3356 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3357 * with il = winAscent + winDescent - units_per_em]
3362 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3363 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3364 pHori
->Ascender
- pHori
->Descender
);
3366 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3367 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3375 static struct font_mapping
*map_font_file( const char *name
)
3377 struct font_mapping
*mapping
;
3381 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3382 if (fstat( fd
, &st
) == -1) goto error
;
3384 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3386 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3388 mapping
->refcount
++;
3393 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3396 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3399 if (mapping
->data
== MAP_FAILED
)
3401 HeapFree( GetProcessHeap(), 0, mapping
);
3404 mapping
->refcount
= 1;
3405 mapping
->dev
= st
.st_dev
;
3406 mapping
->ino
= st
.st_ino
;
3407 mapping
->size
= st
.st_size
;
3408 list_add_tail( &mappings_list
, &mapping
->entry
);
3416 static void unmap_font_file( struct font_mapping
*mapping
)
3418 if (!--mapping
->refcount
)
3420 list_remove( &mapping
->entry
);
3421 munmap( mapping
->data
, mapping
->size
);
3422 HeapFree( GetProcessHeap(), 0, mapping
);
3426 static LONG
load_VDMX(GdiFont
*, LONG
);
3428 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3435 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3439 if (!(font
->mapping
= map_font_file( face
->file
)))
3441 WARN("failed to map %s\n", debugstr_a(face
->file
));
3444 data_ptr
= font
->mapping
->data
;
3445 data_size
= font
->mapping
->size
;
3449 data_ptr
= face
->font_data_ptr
;
3450 data_size
= face
->font_data_size
;
3453 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3455 ERR("FT_New_Face rets %d\n", err
);
3459 /* set it here, as load_VDMX needs it */
3460 font
->ft_face
= ft_face
;
3462 if(FT_IS_SCALABLE(ft_face
)) {
3463 /* load the VDMX table if we have one */
3464 font
->ppem
= load_VDMX(font
, height
);
3466 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3467 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3469 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3470 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3472 font
->ppem
= height
;
3473 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3474 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3480 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3482 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3483 a single face with the requested charset. The idea is to check if
3484 the selected font supports the current ANSI codepage, if it does
3485 return the corresponding charset, else return the first charset */
3488 int acp
= GetACP(), i
;
3492 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3494 const SYSTEM_LINKS
*font_link
;
3496 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
3497 return csi
.ciCharset
;
3499 font_link
= find_font_link(family_name
);
3500 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
3501 return csi
.ciCharset
;
3504 for(i
= 0; i
< 32; i
++) {
3506 if(face
->fs
.fsCsb
[0] & fs0
) {
3507 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3509 return csi
.ciCharset
;
3512 FIXME("TCI failing on %x\n", fs0
);
3516 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3517 face
->fs
.fsCsb
[0], face
->file
);
3519 return DEFAULT_CHARSET
;
3522 static GdiFont
*alloc_font(void)
3524 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3526 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3527 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3529 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3530 ret
->total_kern_pairs
= (DWORD
)-1;
3531 ret
->kern_pairs
= NULL
;
3532 list_init(&ret
->hfontlist
);
3533 list_init(&ret
->child_fonts
);
3537 static void free_font(GdiFont
*font
)
3539 struct list
*cursor
, *cursor2
;
3542 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3544 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3545 list_remove(cursor
);
3547 free_font(child
->font
);
3548 HeapFree(GetProcessHeap(), 0, child
);
3551 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3553 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3554 DeleteObject(hfontlist
->hfont
);
3555 list_remove(&hfontlist
->entry
);
3556 HeapFree(GetProcessHeap(), 0, hfontlist
);
3559 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3560 if (font
->mapping
) unmap_font_file( font
->mapping
);
3561 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3562 HeapFree(GetProcessHeap(), 0, font
->potm
);
3563 HeapFree(GetProcessHeap(), 0, font
->name
);
3564 for (i
= 0; i
< font
->gmsize
; i
++)
3565 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3566 HeapFree(GetProcessHeap(), 0, font
->gm
);
3567 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3568 HeapFree(GetProcessHeap(), 0, font
);
3572 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3574 FT_Face ft_face
= font
->ft_face
;
3578 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3585 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3587 /* make sure value of len is the value freetype says it needs */
3590 FT_ULong needed
= 0;
3591 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3592 if( !err
&& needed
< len
) len
= needed
;
3594 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3597 TRACE("Can't find table %c%c%c%c\n",
3598 /* bytes were reversed */
3599 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3600 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3606 /*************************************************************
3609 * load the vdmx entry for the specified height
3612 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3613 ( ( (FT_ULong)_x4 << 24 ) | \
3614 ( (FT_ULong)_x3 << 16 ) | \
3615 ( (FT_ULong)_x2 << 8 ) | \
3618 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3633 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3637 BYTE devXRatio
, devYRatio
;
3638 USHORT numRecs
, numRatios
;
3639 DWORD result
, offset
= -1;
3643 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3645 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3648 /* FIXME: need the real device aspect ratio */
3652 numRecs
= GET_BE_WORD(hdr
[1]);
3653 numRatios
= GET_BE_WORD(hdr
[2]);
3655 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3656 for(i
= 0; i
< numRatios
; i
++) {
3659 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3660 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3663 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3665 if((ratio
.xRatio
== 0 &&
3666 ratio
.yStartRatio
== 0 &&
3667 ratio
.yEndRatio
== 0) ||
3668 (devXRatio
== ratio
.xRatio
&&
3669 devYRatio
>= ratio
.yStartRatio
&&
3670 devYRatio
<= ratio
.yEndRatio
))
3672 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3673 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3674 offset
= GET_BE_WORD(tmp
);
3680 FIXME("No suitable ratio found\n");
3684 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3686 BYTE startsz
, endsz
;
3689 recs
= GET_BE_WORD(group
.recs
);
3690 startsz
= group
.startsz
;
3691 endsz
= group
.endsz
;
3693 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3695 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3696 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3697 if(result
== GDI_ERROR
) {
3698 FIXME("Failed to retrieve vTable\n");
3703 for(i
= 0; i
< recs
; i
++) {
3704 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3705 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3706 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3708 if(yMax
+ -yMin
== height
) {
3711 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3714 if(yMax
+ -yMin
> height
) {
3717 goto end
; /* failed */
3719 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3720 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3721 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3722 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3728 TRACE("ppem not found for height %d\n", height
);
3732 HeapFree(GetProcessHeap(), 0, vTable
);
3738 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3740 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3741 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3742 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3743 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3744 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3747 static void calc_hash(FONT_DESC
*pfd
)
3749 DWORD hash
= 0, *ptr
, two_chars
;
3753 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3755 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3757 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3759 pwc
= (WCHAR
*)&two_chars
;
3761 *pwc
= toupperW(*pwc
);
3763 *pwc
= toupperW(*pwc
);
3767 hash
^= !pfd
->can_use_bitmap
;
3772 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3777 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3781 fd
.can_use_bitmap
= can_use_bitmap
;
3784 /* try the child list */
3785 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3786 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3787 if(!fontcmp(ret
, &fd
)) {
3788 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3789 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3790 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3791 if(hflist
->hfont
== hfont
)
3797 /* try the in-use list */
3798 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3799 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3800 if(!fontcmp(ret
, &fd
)) {
3801 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3802 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3803 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3804 if(hflist
->hfont
== hfont
)
3807 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3808 hflist
->hfont
= hfont
;
3809 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3814 /* then the unused list */
3815 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3816 while(font_elem_ptr
) {
3817 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3818 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3819 if(!fontcmp(ret
, &fd
)) {
3820 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3821 assert(list_empty(&ret
->hfontlist
));
3822 TRACE("Found %p in unused list\n", ret
);
3823 list_remove(&ret
->entry
);
3824 list_add_head(&gdi_font_list
, &ret
->entry
);
3825 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3826 hflist
->hfont
= hfont
;
3827 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3834 static void add_to_cache(GdiFont
*font
)
3836 static DWORD cache_num
= 1;
3838 font
->cache_num
= cache_num
++;
3839 list_add_head(&gdi_font_list
, &font
->entry
);
3842 /*************************************************************
3843 * create_child_font_list
3845 static BOOL
create_child_font_list(GdiFont
*font
)
3848 SYSTEM_LINKS
*font_link
;
3849 CHILD_FONT
*font_link_entry
, *new_child
;
3853 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3854 font_name
= psub
? psub
->to
.name
: font
->name
;
3855 font_link
= find_font_link(font_name
);
3856 if (font_link
!= NULL
)
3858 TRACE("found entry in system list\n");
3859 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3861 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3862 new_child
->face
= font_link_entry
->face
;
3863 new_child
->font
= NULL
;
3864 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3865 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3870 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3871 * Sans Serif. This is how asian windows get default fallbacks for fonts
3873 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3874 font
->charset
!= OEM_CHARSET
&&
3875 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3877 font_link
= find_font_link(szDefaultFallbackLink
);
3878 if (font_link
!= NULL
)
3880 TRACE("found entry in default fallback list\n");
3881 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3883 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3884 new_child
->face
= font_link_entry
->face
;
3885 new_child
->font
= NULL
;
3886 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3887 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3896 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3898 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3900 if (pFT_Set_Charmap
)
3903 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3905 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3907 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3909 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3911 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3912 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3914 switch (ft_face
->charmaps
[i
]->platform_id
)
3917 cmap_def
= ft_face
->charmaps
[i
];
3919 case 0: /* Apple Unicode */
3920 cmap0
= ft_face
->charmaps
[i
];
3922 case 1: /* Macintosh */
3923 cmap1
= ft_face
->charmaps
[i
];
3926 cmap2
= ft_face
->charmaps
[i
];
3928 case 3: /* Microsoft */
3929 cmap3
= ft_face
->charmaps
[i
];
3934 if (cmap3
) /* prefer Microsoft cmap table */
3935 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3937 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3939 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3941 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3943 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3945 return ft_err
== FT_Err_Ok
;
3948 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3952 /*************************************************************
3955 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
3956 LPCWSTR output
, const DEVMODEW
*devmode
)
3958 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
3960 if (!physdev
) return FALSE
;
3961 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
3966 /*************************************************************
3969 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
3971 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3972 HeapFree( GetProcessHeap(), 0, physdev
);
3977 /*************************************************************
3978 * freetype_SelectFont
3980 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
3982 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3984 Face
*face
, *best
, *best_bitmap
;
3985 Family
*family
, *last_resort_family
;
3986 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
3987 INT height
, width
= 0;
3988 unsigned int score
= 0, new_score
;
3989 signed int diff
= 0, newdiff
;
3990 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
3995 FontSubst
*psub
= NULL
;
3996 DC
*dc
= get_dc_ptr( dev
->hdc
);
3997 const SYSTEM_LINKS
*font_link
;
3999 if (!hfont
) /* notification that the font has been changed by another driver */
4002 physdev
->font
= NULL
;
4003 release_dc_ptr( dc
);
4007 GetObjectW( hfont
, sizeof(lf
), &lf
);
4008 lf
.lfWidth
= abs(lf
.lfWidth
);
4010 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4012 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4013 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4014 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4017 if(dc
->GraphicsMode
== GM_ADVANCED
)
4019 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4020 /* Try to avoid not necessary glyph transformations */
4021 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4023 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4024 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4025 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4030 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4031 font scaling abilities. */
4032 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4033 dcmat
.eM21
= dcmat
.eM12
= 0;
4034 if (dc
->vport2WorldValid
)
4036 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4037 lf
.lfOrientation
= -lf
.lfOrientation
;
4038 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4039 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4043 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4044 dcmat
.eM21
, dcmat
.eM22
);
4047 EnterCriticalSection( &freetype_cs
);
4049 /* check the cache first */
4050 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4051 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4055 if(list_empty(&font_list
)) /* No fonts installed */
4057 TRACE("No fonts installed\n");
4061 TRACE("not in cache\n");
4064 ret
->font_desc
.matrix
= dcmat
;
4065 ret
->font_desc
.lf
= lf
;
4066 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4067 calc_hash(&ret
->font_desc
);
4068 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4069 hflist
->hfont
= hfont
;
4070 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4072 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4073 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4074 original value lfCharSet. Note this is a special case for
4075 Symbol and doesn't happen at least for "Wingdings*" */
4077 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4078 lf
.lfCharSet
= SYMBOL_CHARSET
;
4080 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4081 switch(lf
.lfCharSet
) {
4082 case DEFAULT_CHARSET
:
4083 csi
.fs
.fsCsb
[0] = 0;
4086 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4087 csi
.fs
.fsCsb
[0] = 0;
4093 if(lf
.lfFaceName
[0] != '\0') {
4094 CHILD_FONT
*font_link_entry
;
4095 LPWSTR FaceName
= lf
.lfFaceName
;
4097 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4100 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4101 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4102 if (psub
->to
.charset
!= -1)
4103 lf
.lfCharSet
= psub
->to
.charset
;
4106 /* We want a match on name and charset or just name if
4107 charset was DEFAULT_CHARSET. If the latter then
4108 we fixup the returned charset later in get_nearest_charset
4109 where we'll either use the charset of the current ansi codepage
4110 or if that's unavailable the first charset that the font supports.
4112 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4113 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4114 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4115 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4117 font_link
= find_font_link(family
->FamilyName
);
4118 face_list
= get_face_list_from_family(family
);
4119 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4120 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4121 if (!(face
->scalable
|| can_use_bitmap
))
4123 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4125 if (font_link
!= NULL
&&
4126 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4128 if (!csi
.fs
.fsCsb
[0])
4134 /* Search by full face name. */
4135 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4136 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4137 face_list
= get_face_list_from_family(family
);
4138 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4139 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4140 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4141 (face
->scalable
|| can_use_bitmap
))
4143 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4145 font_link
= find_font_link(family
->FamilyName
);
4146 if (font_link
!= NULL
&&
4147 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4154 * Try check the SystemLink list first for a replacement font.
4155 * We may find good replacements there.
4157 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4159 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4160 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4162 TRACE("found entry in system list\n");
4163 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4165 const SYSTEM_LINKS
*links
;
4167 face
= font_link_entry
->face
;
4168 if (!(face
->scalable
|| can_use_bitmap
))
4170 family
= face
->family
;
4171 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4173 links
= find_font_link(family
->FamilyName
);
4174 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4181 psub
= NULL
; /* substitution is no more relevant */
4183 /* If requested charset was DEFAULT_CHARSET then try using charset
4184 corresponding to the current ansi codepage */
4185 if (!csi
.fs
.fsCsb
[0])
4188 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4189 FIXME("TCI failed on codepage %d\n", acp
);
4190 csi
.fs
.fsCsb
[0] = 0;
4192 lf
.lfCharSet
= csi
.ciCharset
;
4195 want_vertical
= (lf
.lfFaceName
[0] == '@');
4197 /* Face families are in the top 4 bits of lfPitchAndFamily,
4198 so mask with 0xF0 before testing */
4200 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4201 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4202 strcpyW(lf
.lfFaceName
, defFixed
);
4203 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4204 strcpyW(lf
.lfFaceName
, defSerif
);
4205 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4206 strcpyW(lf
.lfFaceName
, defSans
);
4208 strcpyW(lf
.lfFaceName
, defSans
);
4209 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4210 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4211 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4212 font_link
= find_font_link(family
->FamilyName
);
4213 face_list
= get_face_list_from_family(family
);
4214 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4215 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4216 if (!(face
->scalable
|| can_use_bitmap
))
4218 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4220 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4226 last_resort_family
= NULL
;
4227 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4228 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4229 font_link
= find_font_link(family
->FamilyName
);
4230 face_list
= get_face_list_from_family(family
);
4231 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4232 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4233 if(face
->vertical
== want_vertical
&&
4234 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4235 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4238 if(can_use_bitmap
&& !last_resort_family
)
4239 last_resort_family
= family
;
4244 if(last_resort_family
) {
4245 family
= last_resort_family
;
4246 csi
.fs
.fsCsb
[0] = 0;
4250 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4251 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4252 face_list
= get_face_list_from_family(family
);
4253 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4254 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4255 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4256 csi
.fs
.fsCsb
[0] = 0;
4257 WARN("just using first face for now\n");
4260 if(can_use_bitmap
&& !last_resort_family
)
4261 last_resort_family
= family
;
4264 if(!last_resort_family
) {
4265 FIXME("can't find a single appropriate font - bailing\n");
4271 WARN("could only find a bitmap font - this will probably look awful!\n");
4272 family
= last_resort_family
;
4273 csi
.fs
.fsCsb
[0] = 0;
4276 it
= lf
.lfItalic
? 1 : 0;
4277 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4279 height
= lf
.lfHeight
;
4281 face
= best
= best_bitmap
= NULL
;
4282 font_link
= find_font_link(family
->FamilyName
);
4283 face_list
= get_face_list_from_family(family
);
4284 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4286 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4287 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4292 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4293 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4294 new_score
= (italic
^ it
) + (bold
^ bd
);
4295 if(!best
|| new_score
<= score
)
4297 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4298 italic
, bold
, it
, bd
);
4301 if(best
->scalable
&& score
== 0) break;
4305 newdiff
= height
- (signed int)(best
->size
.height
);
4307 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4308 if(!best_bitmap
|| new_score
< score
||
4309 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4311 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4314 if(score
== 0 && diff
== 0) break;
4321 face
= best
->scalable
? best
: best_bitmap
;
4322 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4323 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4326 height
= lf
.lfHeight
;
4330 if(csi
.fs
.fsCsb
[0]) {
4331 ret
->charset
= lf
.lfCharSet
;
4332 ret
->codepage
= csi
.ciACP
;
4335 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4337 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4338 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4340 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4342 if(!face
->scalable
) {
4343 /* Windows uses integer scaling factors for bitmap fonts */
4344 INT scale
, scaled_height
;
4345 GdiFont
*cachedfont
;
4347 /* FIXME: rotation of bitmap fonts is ignored */
4348 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4350 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4351 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4352 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4353 /* As we changed the matrix, we need to search the cache for the font again,
4354 * otherwise we might explode the cache. */
4355 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4356 TRACE("Found cached font after non-scalable matrix rescale!\n");
4361 calc_hash(&ret
->font_desc
);
4363 if (height
!= 0) height
= diff
;
4364 height
+= face
->size
.height
;
4366 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4367 scaled_height
= scale
* face
->size
.height
;
4368 /* Only jump to the next height if the difference <= 25% original height */
4369 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4370 /* The jump between unscaled and doubled is delayed by 1 */
4371 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4372 ret
->scale_y
= scale
;
4374 width
= face
->size
.x_ppem
>> 6;
4375 height
= face
->size
.y_ppem
>> 6;
4379 TRACE("font scale y: %f\n", ret
->scale_y
);
4381 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4390 ret
->ntmFlags
= face
->ntmFlags
;
4392 if (ret
->charset
== SYMBOL_CHARSET
&&
4393 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4396 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4400 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4403 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4404 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4405 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4406 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4407 create_child_font_list(ret
);
4409 if (face
->vertical
) /* We need to try to load the GSUB table */
4411 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4412 if (length
!= GDI_ERROR
)
4414 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4415 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4416 TRACE("Loaded GSUB table of %i bytes\n",length
);
4420 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4427 physdev
->font
= ret
;
4429 LeaveCriticalSection( &freetype_cs
);
4430 release_dc_ptr( dc
);
4431 return ret
? hfont
: 0;
4434 static void dump_gdi_font_list(void)
4437 struct list
*elem_ptr
;
4439 TRACE("---------- gdiFont Cache ----------\n");
4440 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4441 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4442 TRACE("gdiFont=%p %s %d\n",
4443 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4446 TRACE("---------- Unused gdiFont Cache ----------\n");
4447 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4448 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4449 TRACE("gdiFont=%p %s %d\n",
4450 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4453 TRACE("---------- Child gdiFont Cache ----------\n");
4454 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4455 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4456 TRACE("gdiFont=%p %s %d\n",
4457 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4461 /*************************************************************
4462 * WineEngDestroyFontInstance
4464 * free the gdiFont associated with this handle
4467 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4472 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4476 EnterCriticalSection( &freetype_cs
);
4478 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4480 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4481 while(hfontlist_elem_ptr
) {
4482 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4483 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4484 if(hflist
->hfont
== handle
) {
4485 TRACE("removing child font %p from child list\n", gdiFont
);
4486 list_remove(&gdiFont
->entry
);
4487 LeaveCriticalSection( &freetype_cs
);
4493 TRACE("destroying hfont=%p\n", handle
);
4495 dump_gdi_font_list();
4497 font_elem_ptr
= list_head(&gdi_font_list
);
4498 while(font_elem_ptr
) {
4499 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4500 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4502 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4503 while(hfontlist_elem_ptr
) {
4504 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4505 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4506 if(hflist
->hfont
== handle
) {
4507 list_remove(&hflist
->entry
);
4508 HeapFree(GetProcessHeap(), 0, hflist
);
4512 if(list_empty(&gdiFont
->hfontlist
)) {
4513 TRACE("Moving to Unused list\n");
4514 list_remove(&gdiFont
->entry
);
4515 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4520 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4521 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4522 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4523 while(font_elem_ptr
) {
4524 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4525 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4526 TRACE("freeing %p\n", gdiFont
);
4527 list_remove(&gdiFont
->entry
);
4530 LeaveCriticalSection( &freetype_cs
);
4534 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4541 id
+= IDS_FIRST_SCRIPT
;
4542 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4543 if (!rsrc
) return 0;
4544 hMem
= LoadResource( gdi32_module
, rsrc
);
4545 if (!hMem
) return 0;
4547 p
= LockResource( hMem
);
4549 while (id
--) p
+= *p
+ 1;
4551 i
= min(LF_FACESIZE
- 1, *p
);
4552 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4558 /***************************************************
4559 * create_enum_charset_list
4561 * This function creates charset enumeration list because in DEFAULT_CHARSET
4562 * case, the ANSI codepage's charset takes precedence over other charsets.
4563 * This function works as a filter other than DEFAULT_CHARSET case.
4565 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4570 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4571 csi
.fs
.fsCsb
[0] != 0) {
4572 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4573 list
->element
[n
].charset
= csi
.ciCharset
;
4574 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4577 else { /* charset is DEFAULT_CHARSET or invalid. */
4580 /* Set the current codepage's charset as the first element. */
4582 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4583 csi
.fs
.fsCsb
[0] != 0) {
4584 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4585 list
->element
[n
].charset
= csi
.ciCharset
;
4586 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4590 /* Fill out left elements. */
4591 for (i
= 0; i
< 32; i
++) {
4593 fs
.fsCsb
[0] = 1L << i
;
4595 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4596 continue; /* skip, already added. */
4597 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4598 continue; /* skip, this is an invalid fsCsb bit. */
4600 list
->element
[n
].mask
= fs
.fsCsb
[0];
4601 list
->element
[n
].charset
= csi
.ciCharset
;
4602 load_script_name( i
, list
->element
[n
].name
);
4611 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4612 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4617 if (face
->cached_enum_data
)
4620 *pelf
= face
->cached_enum_data
->elf
;
4621 *pntm
= face
->cached_enum_data
->ntm
;
4622 *ptype
= face
->cached_enum_data
->type
;
4626 font
= alloc_font();
4628 if(face
->scalable
) {
4629 height
= -2048; /* 2048 is the most common em size */
4632 height
= face
->size
.y_ppem
>> 6;
4633 width
= face
->size
.x_ppem
>> 6;
4635 font
->scale_y
= 1.0;
4637 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4643 font
->name
= strdupW(face
->family
->FamilyName
);
4644 font
->ntmFlags
= face
->ntmFlags
;
4646 if (get_outline_text_metrics(font
))
4648 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4650 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4652 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4653 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4655 lstrcpynW(pelf
->elfFullName
,
4656 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4658 lstrcpynW(pelf
->elfStyle
,
4659 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4664 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4666 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4668 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4670 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4672 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4673 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4676 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4677 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4678 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4679 pntm
->ntmFontSig
= face
->fs
;
4681 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4683 pelf
->elfLogFont
.lfEscapement
= 0;
4684 pelf
->elfLogFont
.lfOrientation
= 0;
4685 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4686 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4687 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4688 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4689 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4690 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4691 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4692 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4693 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4694 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4695 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4698 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4699 *ptype
|= TRUETYPE_FONTTYPE
;
4700 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4701 *ptype
|= DEVICE_FONTTYPE
;
4702 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4703 *ptype
|= RASTER_FONTTYPE
;
4705 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4706 if (face
->cached_enum_data
)
4708 face
->cached_enum_data
->elf
= *pelf
;
4709 face
->cached_enum_data
->ntm
= *pntm
;
4710 face
->cached_enum_data
->type
= *ptype
;
4716 static void create_full_name(WCHAR
*full_name
, const WCHAR
*family_name
, const WCHAR
*style_name
)
4718 static const WCHAR spaceW
[] = { ' ', 0 };
4720 strcpyW(full_name
, family_name
);
4721 strcatW(full_name
, spaceW
);
4722 strcatW(full_name
, style_name
);
4725 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4727 const struct list
*face_list
, *face_elem_ptr
;
4729 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4731 face_list
= get_face_list_from_family(family
);
4732 LIST_FOR_EACH(face_elem_ptr
, face_list
)
4734 WCHAR full_family_name
[LF_FULLFACESIZE
];
4735 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4737 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4739 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4740 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4744 create_full_name(full_family_name
, family
->FamilyName
, face
->StyleName
);
4745 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4751 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
4753 WCHAR full_family_name
[LF_FULLFACESIZE
];
4755 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
4757 if (strlenW(family_name
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4759 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4760 debugstr_w(family_name
), debugstr_w(face
->StyleName
));
4764 create_full_name(full_family_name
, family_name
, face
->StyleName
);
4765 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4768 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
4769 FONTENUMPROCW proc
, LPARAM lparam
)
4772 NEWTEXTMETRICEXW ntm
;
4776 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4777 for(i
= 0; i
< list
->total
; i
++) {
4778 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4779 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4780 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4781 i
= list
->total
; /* break out of loop after enumeration */
4782 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4785 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4786 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4787 if (!elf
.elfScript
[0])
4788 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4790 /* Font Replacement */
4791 if (family
!= face
->family
)
4793 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
4794 create_full_name(elf
.elfFullName
, family
->FamilyName
, face
->StyleName
);
4796 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4797 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4798 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4799 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4800 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4801 ntm
.ntmTm
.ntmFlags
);
4802 /* release section before callback (FIXME) */
4803 LeaveCriticalSection( &freetype_cs
);
4804 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4805 EnterCriticalSection( &freetype_cs
);
4810 /*************************************************************
4811 * freetype_EnumFonts
4813 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4817 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4819 struct enum_charset_list enum_charsets
;
4823 lf
.lfCharSet
= DEFAULT_CHARSET
;
4824 lf
.lfPitchAndFamily
= 0;
4825 lf
.lfFaceName
[0] = 0;
4829 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4831 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4834 EnterCriticalSection( &freetype_cs
);
4835 if(plf
->lfFaceName
[0]) {
4837 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4840 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4841 debugstr_w(psub
->to
.name
));
4843 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4847 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4848 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4849 if(family_matches(family
, plf
)) {
4850 face_list
= get_face_list_from_family(family
);
4851 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4852 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4853 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
4854 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4859 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4860 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4861 face_list
= get_face_list_from_family(family
);
4862 face_elem_ptr
= list_head(face_list
);
4863 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4864 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4867 LeaveCriticalSection( &freetype_cs
);
4871 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4873 pt
->x
.value
= vec
->x
>> 6;
4874 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4875 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4876 pt
->y
.value
= vec
->y
>> 6;
4877 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4878 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4882 /***************************************************
4883 * According to the MSDN documentation on WideCharToMultiByte,
4884 * certain codepages cannot set the default_used parameter.
4885 * This returns TRUE if the codepage can set that parameter, false else
4886 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4888 static BOOL
codepage_sets_default_used(UINT codepage
)
4902 * GSUB Table handling functions
4905 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4907 const GSUB_CoverageFormat1
* cf1
;
4911 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4913 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4915 TRACE("Coverage Format 1, %i glyphs\n",count
);
4916 for (i
= 0; i
< count
; i
++)
4917 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4921 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4923 const GSUB_CoverageFormat2
* cf2
;
4926 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4928 count
= GET_BE_WORD(cf2
->RangeCount
);
4929 TRACE("Coverage Format 2, %i ranges\n",count
);
4930 for (i
= 0; i
< count
; i
++)
4932 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4934 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4935 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4937 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4938 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4944 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4949 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4951 const GSUB_ScriptList
*script
;
4952 const GSUB_Script
*deflt
= NULL
;
4954 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4956 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4957 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4959 const GSUB_Script
*scr
;
4962 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4963 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4965 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4967 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4973 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4977 const GSUB_LangSys
*Lang
;
4979 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4981 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4983 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4984 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4986 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4989 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4992 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4998 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5001 const GSUB_FeatureList
*feature
;
5002 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5004 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5005 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5007 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5008 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5010 const GSUB_Feature
*feat
;
5011 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5018 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5022 const GSUB_LookupList
*lookup
;
5023 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5025 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5026 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5028 const GSUB_LookupTable
*look
;
5029 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5030 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5031 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5032 if (GET_BE_WORD(look
->LookupType
) != 1)
5033 FIXME("We only handle SubType 1\n");
5038 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5040 const GSUB_SingleSubstFormat1
*ssf1
;
5041 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5042 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5043 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5045 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5046 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5047 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5049 TRACE(" Glyph 0x%x ->",glyph
);
5050 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5051 TRACE(" 0x%x\n",glyph
);
5056 const GSUB_SingleSubstFormat2
*ssf2
;
5060 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5061 offset
= GET_BE_WORD(ssf1
->Coverage
);
5062 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5063 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5064 TRACE(" Coverage index %i\n",index
);
5067 TRACE(" Glyph is 0x%x ->",glyph
);
5068 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5069 TRACE("0x%x\n",glyph
);
5078 static const char* get_opentype_script(const GdiFont
*font
)
5081 * I am not sure if this is the correct way to generate our script tag
5084 switch (font
->charset
)
5086 case ANSI_CHARSET
: return "latn";
5087 case BALTIC_CHARSET
: return "latn"; /* ?? */
5088 case CHINESEBIG5_CHARSET
: return "hani";
5089 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5090 case GB2312_CHARSET
: return "hani";
5091 case GREEK_CHARSET
: return "grek";
5092 case HANGUL_CHARSET
: return "hang";
5093 case RUSSIAN_CHARSET
: return "cyrl";
5094 case SHIFTJIS_CHARSET
: return "kana";
5095 case TURKISH_CHARSET
: return "latn"; /* ?? */
5096 case VIETNAMESE_CHARSET
: return "latn";
5097 case JOHAB_CHARSET
: return "latn"; /* ?? */
5098 case ARABIC_CHARSET
: return "arab";
5099 case HEBREW_CHARSET
: return "hebr";
5100 case THAI_CHARSET
: return "thai";
5101 default: return "latn";
5105 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5107 const GSUB_Header
*header
;
5108 const GSUB_Script
*script
;
5109 const GSUB_LangSys
*language
;
5110 const GSUB_Feature
*feature
;
5112 if (!font
->GSUB_Table
)
5115 header
= font
->GSUB_Table
;
5117 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5120 TRACE("Script not found\n");
5123 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5126 TRACE("Language not found\n");
5129 feature
= GSUB_get_feature(header
, language
, "vrt2");
5131 feature
= GSUB_get_feature(header
, language
, "vert");
5134 TRACE("vrt2/vert feature not found\n");
5137 return GSUB_apply_feature(header
, feature
, glyph
);
5140 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5144 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5145 WCHAR wc
= (WCHAR
)glyph
;
5147 BOOL
*default_used_pointer
;
5150 default_used_pointer
= NULL
;
5151 default_used
= FALSE
;
5152 if (codepage_sets_default_used(font
->codepage
))
5153 default_used_pointer
= &default_used
;
5154 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5157 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5158 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5162 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5164 if (glyph
< 0x100) glyph
+= 0xf000;
5165 /* there is a number of old pre-Unicode "broken" TTFs, which
5166 do have symbols at U+00XX instead of U+f0XX */
5167 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5168 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5170 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5175 /*************************************************************
5176 * freetype_GetGlyphIndices
5178 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5180 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5183 BOOL got_default
= FALSE
;
5187 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5188 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5191 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5193 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5198 EnterCriticalSection( &freetype_cs
);
5200 for(i
= 0; i
< count
; i
++)
5202 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5207 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5209 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5210 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5215 get_text_metrics(physdev
->font
, &textm
);
5216 default_char
= textm
.tmDefaultChar
;
5220 pgi
[i
] = default_char
;
5223 LeaveCriticalSection( &freetype_cs
);
5227 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5229 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5230 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5233 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5235 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5236 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5239 static inline BYTE
get_max_level( UINT format
)
5243 case GGO_GRAY2_BITMAP
: return 4;
5244 case GGO_GRAY4_BITMAP
: return 16;
5245 case GGO_GRAY8_BITMAP
: return 64;
5250 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5252 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5253 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5256 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5257 FT_Face ft_face
= incoming_font
->ft_face
;
5258 GdiFont
*font
= incoming_font
;
5259 FT_UInt glyph_index
;
5260 DWORD width
, height
, pitch
, needed
= 0;
5261 FT_Bitmap ft_bitmap
;
5263 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5265 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5266 double widthRatio
= 1.0;
5267 FT_Matrix transMat
= identityMat
;
5268 FT_Matrix transMatUnrotated
;
5269 BOOL needsTransform
= FALSE
;
5270 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5271 UINT original_index
;
5273 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5274 buflen
, buf
, lpmat
);
5276 TRACE("font transform %f %f %f %f\n",
5277 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5278 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5280 if(format
& GGO_GLYPH_INDEX
) {
5281 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5282 original_index
= glyph
;
5283 format
&= ~GGO_GLYPH_INDEX
;
5285 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5286 ft_face
= font
->ft_face
;
5287 original_index
= glyph_index
;
5290 if(format
& GGO_UNHINTED
) {
5291 load_flags
|= FT_LOAD_NO_HINTING
;
5292 format
&= ~GGO_UNHINTED
;
5295 /* tategaki never appears to happen to lower glyph index */
5296 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5299 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5300 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5301 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5302 font
->gmsize
* sizeof(GM
*));
5304 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5305 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5307 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5308 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5309 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5310 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5311 return 1; /* FIXME */
5315 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5316 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5318 /* Scaling factor */
5323 get_text_metrics(font
, &tm
);
5325 widthRatio
= (double)font
->aveWidth
;
5326 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5329 widthRatio
= font
->scale_y
;
5331 /* Scaling transform */
5332 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5335 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5338 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5340 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5341 needsTransform
= TRUE
;
5344 /* Slant transform */
5345 if (font
->fake_italic
) {
5348 slantMat
.xx
= (1 << 16);
5349 slantMat
.xy
= ((1 << 16) >> 2);
5351 slantMat
.yy
= (1 << 16);
5352 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5353 needsTransform
= TRUE
;
5356 /* Rotation transform */
5357 transMatUnrotated
= transMat
;
5358 if(font
->orientation
&& !tategaki
) {
5359 FT_Matrix rotationMat
;
5361 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5362 pFT_Vector_Unit(&vecAngle
, angle
);
5363 rotationMat
.xx
= vecAngle
.x
;
5364 rotationMat
.xy
= -vecAngle
.y
;
5365 rotationMat
.yx
= -rotationMat
.xy
;
5366 rotationMat
.yy
= rotationMat
.xx
;
5368 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5369 needsTransform
= TRUE
;
5372 /* World transform */
5373 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5376 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5377 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5378 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5379 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5380 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5381 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5382 needsTransform
= TRUE
;
5385 /* Extra transformation specified by caller */
5386 if (!is_identity_MAT2(lpmat
))
5389 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5390 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5391 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5392 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5393 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5394 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5395 needsTransform
= TRUE
;
5398 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5399 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5400 format
== GGO_GRAY8_BITMAP
))
5402 load_flags
|= FT_LOAD_NO_BITMAP
;
5405 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5408 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5412 if(!needsTransform
) {
5413 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5414 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5415 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5417 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5418 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5419 ft_face
->glyph
->metrics
.height
) & -64;
5420 lpgm
->gmCellIncX
= adv
;
5421 lpgm
->gmCellIncY
= 0;
5428 for(xc
= 0; xc
< 2; xc
++) {
5429 for(yc
= 0; yc
< 2; yc
++) {
5430 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5431 xc
* ft_face
->glyph
->metrics
.width
);
5432 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5433 yc
* ft_face
->glyph
->metrics
.height
;
5434 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5435 pFT_Vector_Transform(&vec
, &transMat
);
5436 if(xc
== 0 && yc
== 0) {
5437 left
= right
= vec
.x
;
5438 top
= bottom
= vec
.y
;
5440 if(vec
.x
< left
) left
= vec
.x
;
5441 else if(vec
.x
> right
) right
= vec
.x
;
5442 if(vec
.y
< bottom
) bottom
= vec
.y
;
5443 else if(vec
.y
> top
) top
= vec
.y
;
5448 right
= (right
+ 63) & -64;
5449 bottom
= bottom
& -64;
5450 top
= (top
+ 63) & -64;
5452 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5453 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5455 pFT_Vector_Transform(&vec
, &transMat
);
5456 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5457 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5459 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5461 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5462 adv
= (vec
.x
+63) >> 6;
5466 bbx
= (right
- left
) >> 6;
5467 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5468 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5469 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5470 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5472 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5473 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5474 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5476 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5477 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5479 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5480 FONT_GM(font
,original_index
)->adv
= adv
;
5481 FONT_GM(font
,original_index
)->lsb
= lsb
;
5482 FONT_GM(font
,original_index
)->bbx
= bbx
;
5483 FONT_GM(font
,original_index
)->init
= TRUE
;
5486 if(format
== GGO_METRICS
)
5488 return 1; /* FIXME */
5491 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5492 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5494 TRACE("loaded a bitmap\n");
5500 width
= lpgm
->gmBlackBoxX
;
5501 height
= lpgm
->gmBlackBoxY
;
5502 pitch
= ((width
+ 31) >> 5) << 2;
5503 needed
= pitch
* height
;
5505 if(!buf
|| !buflen
) break;
5507 switch(ft_face
->glyph
->format
) {
5508 case ft_glyph_format_bitmap
:
5510 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5511 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5512 INT h
= ft_face
->glyph
->bitmap
.rows
;
5514 memcpy(dst
, src
, w
);
5515 src
+= ft_face
->glyph
->bitmap
.pitch
;
5521 case ft_glyph_format_outline
:
5522 ft_bitmap
.width
= width
;
5523 ft_bitmap
.rows
= height
;
5524 ft_bitmap
.pitch
= pitch
;
5525 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5526 ft_bitmap
.buffer
= buf
;
5529 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5531 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5533 /* Note: FreeType will only set 'black' bits for us. */
5534 memset(buf
, 0, needed
);
5535 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5539 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5544 case GGO_GRAY2_BITMAP
:
5545 case GGO_GRAY4_BITMAP
:
5546 case GGO_GRAY8_BITMAP
:
5547 case WINE_GGO_GRAY16_BITMAP
:
5549 unsigned int max_level
, row
, col
;
5552 width
= lpgm
->gmBlackBoxX
;
5553 height
= lpgm
->gmBlackBoxY
;
5554 pitch
= (width
+ 3) / 4 * 4;
5555 needed
= pitch
* height
;
5557 if(!buf
|| !buflen
) break;
5559 max_level
= get_max_level( format
);
5561 switch(ft_face
->glyph
->format
) {
5562 case ft_glyph_format_bitmap
:
5564 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5565 INT h
= ft_face
->glyph
->bitmap
.rows
;
5567 memset( buf
, 0, needed
);
5569 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5570 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5571 src
+= ft_face
->glyph
->bitmap
.pitch
;
5576 case ft_glyph_format_outline
:
5578 ft_bitmap
.width
= width
;
5579 ft_bitmap
.rows
= height
;
5580 ft_bitmap
.pitch
= pitch
;
5581 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5582 ft_bitmap
.buffer
= buf
;
5585 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5587 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5589 memset(ft_bitmap
.buffer
, 0, buflen
);
5591 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5593 if (max_level
!= 255)
5595 for (row
= 0, start
= buf
; row
< height
; row
++)
5597 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5598 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5606 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5612 case WINE_GGO_HRGB_BITMAP
:
5613 case WINE_GGO_HBGR_BITMAP
:
5614 case WINE_GGO_VRGB_BITMAP
:
5615 case WINE_GGO_VBGR_BITMAP
:
5616 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5618 switch (ft_face
->glyph
->format
)
5620 case FT_GLYPH_FORMAT_BITMAP
:
5625 width
= lpgm
->gmBlackBoxX
;
5626 height
= lpgm
->gmBlackBoxY
;
5628 needed
= pitch
* height
;
5630 if (!buf
|| !buflen
) break;
5632 memset(buf
, 0, buflen
);
5634 src
= ft_face
->glyph
->bitmap
.buffer
;
5635 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5637 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5640 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5642 if ( src
[x
/ 8] & masks
[x
% 8] )
5643 ((unsigned int *)dst
)[x
] = ~0u;
5652 case FT_GLYPH_FORMAT_OUTLINE
:
5656 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5657 INT x_shift
, y_shift
;
5659 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5660 FT_Render_Mode render_mode
=
5661 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5662 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5664 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5666 if ( render_mode
== FT_RENDER_MODE_LCD
)
5668 lpgm
->gmBlackBoxX
+= 2;
5669 lpgm
->gmptGlyphOrigin
.x
-= 1;
5673 lpgm
->gmBlackBoxY
+= 2;
5674 lpgm
->gmptGlyphOrigin
.y
+= 1;
5678 width
= lpgm
->gmBlackBoxX
;
5679 height
= lpgm
->gmBlackBoxY
;
5681 needed
= pitch
* height
;
5683 if (!buf
|| !buflen
) break;
5685 memset(buf
, 0, buflen
);
5687 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5689 if ( needsTransform
)
5690 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5692 if ( pFT_Library_SetLcdFilter
)
5693 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5694 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5696 src
= ft_face
->glyph
->bitmap
.buffer
;
5697 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5698 src_width
= ft_face
->glyph
->bitmap
.width
;
5699 src_height
= ft_face
->glyph
->bitmap
.rows
;
5701 if ( render_mode
== FT_RENDER_MODE_LCD
)
5709 rgb_interval
= src_pitch
;
5714 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5715 if ( x_shift
< 0 ) x_shift
= 0;
5716 if ( x_shift
+ (src_width
/ hmul
) > width
)
5717 x_shift
= width
- (src_width
/ hmul
);
5719 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5720 if ( y_shift
< 0 ) y_shift
= 0;
5721 if ( y_shift
+ (src_height
/ vmul
) > height
)
5722 y_shift
= height
- (src_height
/ vmul
);
5724 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5725 while ( src_height
)
5727 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5731 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5732 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5733 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5734 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5738 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5739 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5740 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5741 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5744 src
+= src_pitch
* vmul
;
5753 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5765 int contour
, point
= 0, first_pt
;
5766 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5767 TTPOLYGONHEADER
*pph
;
5769 DWORD pph_start
, cpfx
, type
;
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_QSPLINE
;
5794 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5797 } while(point
<= outline
->contours
[contour
] &&
5798 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5799 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5800 /* At the end of a contour Windows adds the start point, but
5802 if(point
> outline
->contours
[contour
] &&
5803 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5805 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5807 } else if(point
<= outline
->contours
[contour
] &&
5808 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5809 /* add closing pt for bezier */
5811 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5819 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5822 pph
->cb
= needed
- pph_start
;
5828 /* Convert the quadratic Beziers to cubic Beziers.
5829 The parametric eqn for a cubic Bezier is, from PLRM:
5830 r(t) = at^3 + bt^2 + ct + r0
5831 with the control points:
5836 A quadratic Bezier has the form:
5837 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5839 So equating powers of t leads to:
5840 r1 = 2/3 p1 + 1/3 p0
5841 r2 = 2/3 p1 + 1/3 p2
5842 and of course r0 = p0, r3 = p2
5845 int contour
, point
= 0, first_pt
;
5846 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5847 TTPOLYGONHEADER
*pph
;
5849 DWORD pph_start
, cpfx
, type
;
5850 FT_Vector cubic_control
[4];
5851 if(buflen
== 0) buf
= NULL
;
5853 if (needsTransform
&& buf
) {
5854 pFT_Outline_Transform(outline
, &transMat
);
5857 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5859 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5862 pph
->dwType
= TT_POLYGON_TYPE
;
5863 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5865 needed
+= sizeof(*pph
);
5867 while(point
<= outline
->contours
[contour
]) {
5868 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5869 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5870 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5873 if(type
== TT_PRIM_LINE
) {
5875 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5879 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5882 /* FIXME: Possible optimization in endpoint calculation
5883 if there are two consecutive curves */
5884 cubic_control
[0] = outline
->points
[point
-1];
5885 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5886 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5887 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5888 cubic_control
[0].x
>>= 1;
5889 cubic_control
[0].y
>>= 1;
5891 if(point
+1 > outline
->contours
[contour
])
5892 cubic_control
[3] = outline
->points
[first_pt
];
5894 cubic_control
[3] = outline
->points
[point
+1];
5895 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5896 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5897 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5898 cubic_control
[3].x
>>= 1;
5899 cubic_control
[3].y
>>= 1;
5902 /* r1 = 1/3 p0 + 2/3 p1
5903 r2 = 1/3 p2 + 2/3 p1 */
5904 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5905 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5906 cubic_control
[2] = cubic_control
[1];
5907 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5908 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5909 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5910 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5912 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5913 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5914 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5919 } while(point
<= outline
->contours
[contour
] &&
5920 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5921 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5922 /* At the end of a contour Windows adds the start point,
5923 but only for Beziers and we've already done that.
5925 if(point
<= outline
->contours
[contour
] &&
5926 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5927 /* This is the closing pt of a bezier, but we've already
5928 added it, so just inc point and carry on */
5935 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5938 pph
->cb
= needed
- pph_start
;
5944 FIXME("Unsupported format %d\n", format
);
5950 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5952 FT_Face ft_face
= font
->ft_face
;
5953 FT_WinFNT_HeaderRec winfnt_header
;
5954 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5955 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5956 font
->potm
->otmSize
= size
;
5958 #define TM font->potm->otmTextMetrics
5959 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5961 TM
.tmHeight
= winfnt_header
.pixel_height
;
5962 TM
.tmAscent
= winfnt_header
.ascent
;
5963 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5964 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5965 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5966 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5967 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5968 TM
.tmWeight
= winfnt_header
.weight
;
5970 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5971 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5972 TM
.tmFirstChar
= winfnt_header
.first_char
;
5973 TM
.tmLastChar
= winfnt_header
.last_char
;
5974 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5975 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5976 TM
.tmItalic
= winfnt_header
.italic
;
5977 TM
.tmUnderlined
= font
->underline
;
5978 TM
.tmStruckOut
= font
->strikeout
;
5979 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5980 TM
.tmCharSet
= winfnt_header
.charset
;
5984 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5985 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5986 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5987 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5988 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5989 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5990 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5991 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5993 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5994 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5996 TM
.tmLastChar
= 255;
5997 TM
.tmDefaultChar
= 32;
5998 TM
.tmBreakChar
= 32;
5999 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6000 TM
.tmUnderlined
= font
->underline
;
6001 TM
.tmStruckOut
= font
->strikeout
;
6002 /* NB inverted meaning of TMPF_FIXED_PITCH */
6003 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6004 TM
.tmCharSet
= font
->charset
;
6012 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6014 double scale_x
, scale_y
;
6018 scale_x
= (double)font
->aveWidth
;
6019 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6022 scale_x
= font
->scale_y
;
6024 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6025 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6027 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6028 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6030 SCALE_Y(ptm
->tmHeight
);
6031 SCALE_Y(ptm
->tmAscent
);
6032 SCALE_Y(ptm
->tmDescent
);
6033 SCALE_Y(ptm
->tmInternalLeading
);
6034 SCALE_Y(ptm
->tmExternalLeading
);
6035 SCALE_Y(ptm
->tmOverhang
);
6037 SCALE_X(ptm
->tmAveCharWidth
);
6038 SCALE_X(ptm
->tmMaxCharWidth
);
6044 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6046 double scale_x
, scale_y
;
6050 scale_x
= (double)font
->aveWidth
;
6051 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6054 scale_x
= font
->scale_y
;
6056 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6057 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6059 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6061 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6062 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6064 SCALE_Y(potm
->otmAscent
);
6065 SCALE_Y(potm
->otmDescent
);
6066 SCALE_Y(potm
->otmLineGap
);
6067 SCALE_Y(potm
->otmsCapEmHeight
);
6068 SCALE_Y(potm
->otmsXHeight
);
6069 SCALE_Y(potm
->otmrcFontBox
.top
);
6070 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6071 SCALE_X(potm
->otmrcFontBox
.left
);
6072 SCALE_X(potm
->otmrcFontBox
.right
);
6073 SCALE_Y(potm
->otmMacAscent
);
6074 SCALE_Y(potm
->otmMacDescent
);
6075 SCALE_Y(potm
->otmMacLineGap
);
6076 SCALE_X(potm
->otmptSubscriptSize
.x
);
6077 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6078 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6079 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6080 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6081 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6082 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6083 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6084 SCALE_Y(potm
->otmsStrikeoutSize
);
6085 SCALE_Y(potm
->otmsStrikeoutPosition
);
6086 SCALE_Y(potm
->otmsUnderscoreSize
);
6087 SCALE_Y(potm
->otmsUnderscorePosition
);
6093 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6097 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6099 /* Make sure that the font has sane width/height ratio */
6102 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6104 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6109 *ptm
= font
->potm
->otmTextMetrics
;
6110 scale_font_metrics(font
, ptm
);
6114 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6118 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6120 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6126 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6129 FT_Face ft_face
= font
->ft_face
;
6130 UINT needed
, lenfam
, lensty
;
6132 TT_HoriHeader
*pHori
;
6133 TT_Postscript
*pPost
;
6134 FT_Fixed x_scale
, y_scale
;
6135 WCHAR
*family_nameW
, *style_nameW
;
6136 static const WCHAR spaceW
[] = {' ', '\0'};
6138 INT ascent
, descent
;
6140 TRACE("font=%p\n", font
);
6142 if(!FT_IS_SCALABLE(ft_face
))
6145 needed
= sizeof(*font
->potm
);
6147 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6148 family_nameW
= strdupW(font
->name
);
6150 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6152 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6153 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6154 style_nameW
, lensty
/sizeof(WCHAR
));
6156 /* These names should be read from the TT name table */
6158 /* length of otmpFamilyName */
6161 /* length of otmpFaceName */
6162 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6163 needed
+= lenfam
; /* just the family name */
6165 needed
+= lenfam
+ lensty
; /* family + " " + style */
6168 /* length of otmpStyleName */
6171 /* length of otmpFullName */
6172 needed
+= lenfam
+ lensty
;
6175 x_scale
= ft_face
->size
->metrics
.x_scale
;
6176 y_scale
= ft_face
->size
->metrics
.y_scale
;
6178 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6180 FIXME("Can't find OS/2 table - not TT font?\n");
6184 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6186 FIXME("Can't find HHEA table - not TT font?\n");
6190 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6192 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",
6193 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6194 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6195 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6196 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6197 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6199 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6200 font
->potm
->otmSize
= needed
;
6202 #define TM font->potm->otmTextMetrics
6204 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6205 ascent
= pHori
->Ascender
;
6206 descent
= -pHori
->Descender
;
6208 ascent
= pOS2
->usWinAscent
;
6209 descent
= pOS2
->usWinDescent
;
6213 TM
.tmAscent
= font
->yMax
;
6214 TM
.tmDescent
= -font
->yMin
;
6215 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6217 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6218 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6219 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6220 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6223 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6226 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6228 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6229 ((ascent
+ descent
) -
6230 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6232 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6233 if (TM
.tmAveCharWidth
== 0) {
6234 TM
.tmAveCharWidth
= 1;
6236 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6237 TM
.tmWeight
= FW_REGULAR
;
6238 if (font
->fake_bold
)
6239 TM
.tmWeight
= FW_BOLD
;
6242 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6244 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6245 TM
.tmWeight
= pOS2
->usWeightClass
;
6247 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6248 TM
.tmWeight
= pOS2
->usWeightClass
;
6251 TM
.tmDigitizedAspectX
= 300;
6252 TM
.tmDigitizedAspectY
= 300;
6253 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6254 * symbol range to 0 - f0ff
6257 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6262 case 1257: /* Baltic */
6263 TM
.tmLastChar
= 0xf8fd;
6266 TM
.tmLastChar
= 0xf0ff;
6268 TM
.tmBreakChar
= 0x20;
6269 TM
.tmDefaultChar
= 0x1f;
6273 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6274 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6276 if(pOS2
->usFirstCharIndex
<= 1)
6277 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6278 else if (pOS2
->usFirstCharIndex
> 0xff)
6279 TM
.tmBreakChar
= 0x20;
6281 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6282 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6284 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6285 TM
.tmUnderlined
= font
->underline
;
6286 TM
.tmStruckOut
= font
->strikeout
;
6288 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6289 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6290 (pOS2
->version
== 0xFFFFU
||
6291 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6292 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6294 TM
.tmPitchAndFamily
= 0;
6296 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6298 case PAN_FAMILY_SCRIPT
:
6299 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6302 case PAN_FAMILY_DECORATIVE
:
6303 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6308 case PAN_FAMILY_TEXT_DISPLAY
:
6309 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6310 /* which is clearly not what the panose spec says. */
6312 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6313 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6314 TM
.tmPitchAndFamily
= FF_MODERN
;
6317 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6322 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6325 case PAN_SERIF_COVE
:
6326 case PAN_SERIF_OBTUSE_COVE
:
6327 case PAN_SERIF_SQUARE_COVE
:
6328 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6329 case PAN_SERIF_SQUARE
:
6330 case PAN_SERIF_THIN
:
6331 case PAN_SERIF_BONE
:
6332 case PAN_SERIF_EXAGGERATED
:
6333 case PAN_SERIF_TRIANGLE
:
6334 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6337 case PAN_SERIF_NORMAL_SANS
:
6338 case PAN_SERIF_OBTUSE_SANS
:
6339 case PAN_SERIF_PERP_SANS
:
6340 case PAN_SERIF_FLARED
:
6341 case PAN_SERIF_ROUNDED
:
6342 TM
.tmPitchAndFamily
|= FF_SWISS
;
6349 if(FT_IS_SCALABLE(ft_face
))
6350 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6352 if(FT_IS_SFNT(ft_face
))
6354 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6355 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6357 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6360 TM
.tmCharSet
= font
->charset
;
6362 font
->potm
->otmFiller
= 0;
6363 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6364 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6365 font
->potm
->otmfsType
= pOS2
->fsType
;
6366 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6367 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6368 font
->potm
->otmItalicAngle
= 0; /* POST table */
6369 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6370 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6371 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6372 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6373 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6374 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6375 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6376 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6377 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6378 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6379 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6380 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6381 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6382 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6383 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6384 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6385 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6386 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6387 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6388 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6389 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6390 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6391 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6392 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6394 font
->potm
->otmsUnderscoreSize
= 0;
6395 font
->potm
->otmsUnderscorePosition
= 0;
6397 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6398 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6402 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6403 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6404 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6405 strcpyW((WCHAR
*)cp
, family_nameW
);
6407 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6408 strcpyW((WCHAR
*)cp
, style_nameW
);
6410 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6411 strcpyW((WCHAR
*)cp
, family_nameW
);
6412 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6413 strcatW((WCHAR
*)cp
, spaceW
);
6414 strcatW((WCHAR
*)cp
, style_nameW
);
6415 cp
+= lenfam
+ lensty
;
6418 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6419 strcpyW((WCHAR
*)cp
, family_nameW
);
6420 strcatW((WCHAR
*)cp
, spaceW
);
6421 strcatW((WCHAR
*)cp
, style_nameW
);
6425 HeapFree(GetProcessHeap(), 0, style_nameW
);
6426 HeapFree(GetProcessHeap(), 0, family_nameW
);
6430 /*************************************************************
6431 * freetype_GetGlyphOutline
6433 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6434 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6436 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6441 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6442 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6446 EnterCriticalSection( &freetype_cs
);
6447 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6448 LeaveCriticalSection( &freetype_cs
);
6452 /*************************************************************
6453 * freetype_GetTextMetrics
6455 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6457 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6462 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6463 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6467 EnterCriticalSection( &freetype_cs
);
6468 ret
= get_text_metrics( physdev
->font
, metrics
);
6469 LeaveCriticalSection( &freetype_cs
);
6473 /*************************************************************
6474 * freetype_GetOutlineTextMetrics
6476 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6478 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6483 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6484 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6487 TRACE("font=%p\n", physdev
->font
);
6489 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6492 EnterCriticalSection( &freetype_cs
);
6494 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6496 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6498 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6499 scale_outline_font_metrics(physdev
->font
, potm
);
6501 ret
= physdev
->font
->potm
->otmSize
;
6503 LeaveCriticalSection( &freetype_cs
);
6507 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6509 HFONTLIST
*hfontlist
;
6510 child
->font
= alloc_font();
6511 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6512 if(!child
->font
->ft_face
)
6514 free_font(child
->font
);
6519 child
->font
->font_desc
= font
->font_desc
;
6520 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6521 child
->font
->orientation
= font
->orientation
;
6522 child
->font
->scale_y
= font
->scale_y
;
6523 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6524 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6525 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6526 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6527 child
->font
->base_font
= font
;
6528 list_add_head(&child_font_list
, &child
->font
->entry
);
6529 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6533 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6536 CHILD_FONT
*child_font
;
6539 font
= font
->base_font
;
6541 *linked_font
= font
;
6543 if((*glyph
= get_glyph_index(font
, c
)))
6545 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6549 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6551 if(!child_font
->font
)
6552 if(!load_child_font(font
, child_font
))
6555 if(!child_font
->font
->ft_face
)
6557 g
= get_glyph_index(child_font
->font
, c
);
6558 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6562 *linked_font
= child_font
->font
;
6569 /*************************************************************
6570 * freetype_GetCharWidth
6572 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6574 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6577 FT_UInt glyph_index
;
6578 GdiFont
*linked_font
;
6579 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6583 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6584 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6587 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6590 EnterCriticalSection( &freetype_cs
);
6591 for(c
= firstChar
; c
<= lastChar
; c
++) {
6592 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6593 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6594 &gm
, 0, NULL
, &identity
);
6595 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6597 LeaveCriticalSection( &freetype_cs
);
6601 /*************************************************************
6602 * freetype_GetCharABCWidths
6604 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6606 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6609 FT_UInt glyph_index
;
6610 GdiFont
*linked_font
;
6611 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6615 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6616 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6619 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6622 EnterCriticalSection( &freetype_cs
);
6624 for(c
= firstChar
; c
<= lastChar
; c
++) {
6625 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6626 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6627 &gm
, 0, NULL
, &identity
);
6628 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6629 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6630 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6631 FONT_GM(linked_font
,glyph_index
)->bbx
;
6633 LeaveCriticalSection( &freetype_cs
);
6637 /*************************************************************
6638 * freetype_GetCharABCWidthsI
6640 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6642 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6645 FT_UInt glyph_index
;
6646 GdiFont
*linked_font
;
6647 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6651 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6652 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6655 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6659 EnterCriticalSection( &freetype_cs
);
6661 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6663 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6664 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6665 &gm
, 0, NULL
, &identity
);
6666 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6667 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6668 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6669 - FONT_GM(linked_font
,c
)->bbx
;
6672 for(c
= 0; c
< count
; c
++) {
6673 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6674 &gm
, 0, NULL
, &identity
);
6675 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6676 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6677 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6678 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6681 LeaveCriticalSection( &freetype_cs
);
6685 /*************************************************************
6686 * freetype_GetTextExtentExPoint
6688 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6689 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6691 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6696 FT_UInt glyph_index
;
6697 GdiFont
*linked_font
;
6698 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6702 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6703 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6706 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6709 EnterCriticalSection( &freetype_cs
);
6712 get_text_metrics( physdev
->font
, &tm
);
6713 size
->cy
= tm
.tmHeight
;
6715 for(idx
= 0; idx
< count
; idx
++) {
6716 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6717 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6718 &gm
, 0, NULL
, &identity
);
6719 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6721 if (! pnfit
|| ext
<= max_ext
) {
6731 LeaveCriticalSection( &freetype_cs
);
6732 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6736 /*************************************************************
6737 * freetype_GetTextExtentExPointI
6739 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6740 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6742 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6747 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6751 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6752 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6755 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6758 EnterCriticalSection( &freetype_cs
);
6761 get_text_metrics(physdev
->font
, &tm
);
6762 size
->cy
= tm
.tmHeight
;
6764 for(idx
= 0; idx
< count
; idx
++) {
6765 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6766 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6768 if (! pnfit
|| ext
<= max_ext
) {
6778 LeaveCriticalSection( &freetype_cs
);
6779 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6783 /*************************************************************
6784 * freetype_GetFontData
6786 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6788 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6792 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6793 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6796 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6797 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6798 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6800 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6803 /*************************************************************
6804 * freetype_GetTextFace
6806 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6809 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6813 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6814 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6817 n
= strlenW(physdev
->font
->name
) + 1;
6820 lstrcpynW(str
, physdev
->font
->name
, count
);
6826 /*************************************************************
6827 * freetype_GetTextCharsetInfo
6829 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6831 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6835 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6836 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6838 if (fs
) *fs
= physdev
->font
->fs
;
6839 return physdev
->font
->charset
;
6842 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6844 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6845 struct list
*first_hfont
;
6849 EnterCriticalSection( &freetype_cs
);
6850 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6851 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6852 if(font
== linked_font
)
6853 *new_hfont
= dc
->hFont
;
6856 first_hfont
= list_head(&linked_font
->hfontlist
);
6857 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6859 LeaveCriticalSection( &freetype_cs
);
6863 /* Retrieve a list of supported Unicode ranges for a given font.
6864 * Can be called with NULL gs to calculate the buffer size. Returns
6865 * the number of ranges found.
6867 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6869 DWORD num_ranges
= 0;
6871 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6874 FT_ULong char_code
, char_code_prev
;
6877 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6879 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6880 face
->num_glyphs
, glyph_code
, char_code
);
6882 if (!glyph_code
) return 0;
6886 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6887 gs
->ranges
[0].cGlyphs
= 0;
6888 gs
->cGlyphsSupported
= 0;
6894 if (char_code
< char_code_prev
)
6896 ERR("expected increasing char code from FT_Get_Next_Char\n");
6899 if (char_code
- char_code_prev
> 1)
6904 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6905 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6906 gs
->cGlyphsSupported
++;
6911 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6912 gs
->cGlyphsSupported
++;
6914 char_code_prev
= char_code
;
6915 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6919 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6924 /*************************************************************
6925 * freetype_GetFontUnicodeRanges
6927 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6929 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6930 DWORD size
, num_ranges
;
6934 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6935 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6938 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6939 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6942 glyphset
->cbThis
= size
;
6943 glyphset
->cRanges
= num_ranges
;
6944 glyphset
->flAccel
= 0;
6949 /*************************************************************
6950 * freetype_FontIsLinked
6952 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6954 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6959 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6960 return dev
->funcs
->pFontIsLinked( dev
);
6964 EnterCriticalSection( &freetype_cs
);
6965 ret
= !list_empty(&physdev
->font
->child_fonts
);
6966 LeaveCriticalSection( &freetype_cs
);
6970 static BOOL
is_hinting_enabled(void)
6972 /* Use the >= 2.2.0 function if available */
6973 if(pFT_Get_TrueType_Engine_Type
)
6975 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6976 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6978 #ifdef FT_DRIVER_HAS_HINTER
6983 /* otherwise if we've been compiled with < 2.2.0 headers
6984 use the internal macro */
6985 mod
= pFT_Get_Module(library
, "truetype");
6986 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6994 static BOOL
is_subpixel_rendering_enabled( void )
6996 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6997 return pFT_Library_SetLcdFilter
&&
6998 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
7004 /*************************************************************************
7005 * GetRasterizerCaps (GDI32.@)
7007 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7009 static int hinting
= -1;
7010 static int subpixel
= -1;
7014 hinting
= is_hinting_enabled();
7015 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
7018 if ( subpixel
== -1 )
7020 subpixel
= is_subpixel_rendering_enabled();
7021 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
7024 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7025 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
7027 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
7028 lprs
->nLanguageID
= 0;
7032 /*************************************************************
7033 * freetype_GdiRealizationInfo
7035 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7037 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7038 realization_info_t
*info
= ptr
;
7042 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7043 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7046 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7049 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7052 info
->cache_num
= physdev
->font
->cache_num
;
7053 info
->unknown2
= -1;
7057 /*************************************************************************
7058 * Kerning support for TrueType fonts
7060 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7062 struct TT_kern_table
7068 struct TT_kern_subtable
7077 USHORT horizontal
: 1;
7079 USHORT cross_stream
: 1;
7080 USHORT override
: 1;
7081 USHORT reserved1
: 4;
7087 struct TT_format0_kern_subtable
7091 USHORT entrySelector
;
7102 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7103 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7104 const USHORT
*glyph_to_char
,
7105 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7108 const struct TT_kern_pair
*tt_kern_pair
;
7110 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7112 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7114 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7115 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7116 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7118 if (!kern_pair
|| !cPairs
)
7121 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7123 nPairs
= min(nPairs
, cPairs
);
7125 for (i
= 0; i
< nPairs
; i
++)
7127 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7128 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7129 /* this algorithm appears to better match what Windows does */
7130 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7131 if (kern_pair
->iKernAmount
< 0)
7133 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7134 kern_pair
->iKernAmount
-= font
->ppem
;
7136 else if (kern_pair
->iKernAmount
> 0)
7138 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7139 kern_pair
->iKernAmount
+= font
->ppem
;
7141 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7143 TRACE("left %u right %u value %d\n",
7144 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7148 TRACE("copied %u entries\n", nPairs
);
7152 /*************************************************************
7153 * freetype_GetKerningPairs
7155 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7159 const struct TT_kern_table
*tt_kern_table
;
7160 const struct TT_kern_subtable
*tt_kern_subtable
;
7162 USHORT
*glyph_to_char
;
7164 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7166 if (!(font
= physdev
->font
))
7168 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7169 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7173 EnterCriticalSection( &freetype_cs
);
7174 if (font
->total_kern_pairs
!= (DWORD
)-1)
7176 if (cPairs
&& kern_pair
)
7178 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7179 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7181 else cPairs
= font
->total_kern_pairs
;
7183 LeaveCriticalSection( &freetype_cs
);
7187 font
->total_kern_pairs
= 0;
7189 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7191 if (length
== GDI_ERROR
)
7193 TRACE("no kerning data in the font\n");
7194 LeaveCriticalSection( &freetype_cs
);
7198 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7201 WARN("Out of memory\n");
7202 LeaveCriticalSection( &freetype_cs
);
7206 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7208 /* build a glyph index to char code map */
7209 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7212 WARN("Out of memory allocating a glyph index to char code map\n");
7213 HeapFree(GetProcessHeap(), 0, buf
);
7214 LeaveCriticalSection( &freetype_cs
);
7218 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7224 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7226 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7227 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7231 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7233 /* FIXME: This doesn't match what Windows does: it does some fancy
7234 * things with duplicate glyph index to char code mappings, while
7235 * we just avoid overriding existing entries.
7237 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7238 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7240 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7247 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7248 for (n
= 0; n
<= 65535; n
++)
7249 glyph_to_char
[n
] = (USHORT
)n
;
7252 tt_kern_table
= buf
;
7253 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7254 TRACE("version %u, nTables %u\n",
7255 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7257 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7259 for (i
= 0; i
< nTables
; i
++)
7261 struct TT_kern_subtable tt_kern_subtable_copy
;
7263 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7264 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7265 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7267 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7268 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7269 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7271 /* According to the TrueType specification this is the only format
7272 * that will be properly interpreted by Windows and OS/2
7274 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7276 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7278 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7279 glyph_to_char
, NULL
, 0);
7280 font
->total_kern_pairs
+= new_chunk
;
7282 if (!font
->kern_pairs
)
7283 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7284 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7286 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7287 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7289 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7290 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7293 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7295 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7298 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7299 HeapFree(GetProcessHeap(), 0, buf
);
7301 if (cPairs
&& kern_pair
)
7303 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7304 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7306 else cPairs
= font
->total_kern_pairs
;
7308 LeaveCriticalSection( &freetype_cs
);
7312 static const struct gdi_dc_funcs freetype_funcs
=
7314 NULL
, /* pAbortDoc */
7315 NULL
, /* pAbortPath */
7316 NULL
, /* pAlphaBlend */
7317 NULL
, /* pAngleArc */
7320 NULL
, /* pBeginPath */
7321 NULL
, /* pBlendImage */
7322 NULL
, /* pChoosePixelFormat */
7324 NULL
, /* pCloseFigure */
7325 NULL
, /* pCopyBitmap */
7326 NULL
, /* pCreateBitmap */
7327 NULL
, /* pCreateCompatibleDC */
7328 freetype_CreateDC
, /* pCreateDC */
7329 NULL
, /* pDeleteBitmap */
7330 freetype_DeleteDC
, /* pDeleteDC */
7331 NULL
, /* pDeleteObject */
7332 NULL
, /* pDescribePixelFormat */
7333 NULL
, /* pDeviceCapabilities */
7334 NULL
, /* pEllipse */
7336 NULL
, /* pEndPage */
7337 NULL
, /* pEndPath */
7338 freetype_EnumFonts
, /* pEnumFonts */
7339 NULL
, /* pEnumICMProfiles */
7340 NULL
, /* pExcludeClipRect */
7341 NULL
, /* pExtDeviceMode */
7342 NULL
, /* pExtEscape */
7343 NULL
, /* pExtFloodFill */
7344 NULL
, /* pExtSelectClipRgn */
7345 NULL
, /* pExtTextOut */
7346 NULL
, /* pFillPath */
7347 NULL
, /* pFillRgn */
7348 NULL
, /* pFlattenPath */
7349 freetype_FontIsLinked
, /* pFontIsLinked */
7350 NULL
, /* pFrameRgn */
7351 NULL
, /* pGdiComment */
7352 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7353 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7354 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7355 freetype_GetCharWidth
, /* pGetCharWidth */
7356 NULL
, /* pGetDeviceCaps */
7357 NULL
, /* pGetDeviceGammaRamp */
7358 freetype_GetFontData
, /* pGetFontData */
7359 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7360 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7361 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7362 NULL
, /* pGetICMProfile */
7363 NULL
, /* pGetImage */
7364 freetype_GetKerningPairs
, /* pGetKerningPairs */
7365 NULL
, /* pGetNearestColor */
7366 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7367 NULL
, /* pGetPixel */
7368 NULL
, /* pGetPixelFormat */
7369 NULL
, /* pGetSystemPaletteEntries */
7370 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7371 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7372 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7373 freetype_GetTextFace
, /* pGetTextFace */
7374 freetype_GetTextMetrics
, /* pGetTextMetrics */
7375 NULL
, /* pGradientFill */
7376 NULL
, /* pIntersectClipRect */
7377 NULL
, /* pInvertRgn */
7379 NULL
, /* pModifyWorldTransform */
7381 NULL
, /* pOffsetClipRgn */
7382 NULL
, /* pOffsetViewportOrg */
7383 NULL
, /* pOffsetWindowOrg */
7384 NULL
, /* pPaintRgn */
7387 NULL
, /* pPolyBezier */
7388 NULL
, /* pPolyBezierTo */
7389 NULL
, /* pPolyDraw */
7390 NULL
, /* pPolyPolygon */
7391 NULL
, /* pPolyPolyline */
7392 NULL
, /* pPolygon */
7393 NULL
, /* pPolyline */
7394 NULL
, /* pPolylineTo */
7395 NULL
, /* pPutImage */
7396 NULL
, /* pRealizeDefaultPalette */
7397 NULL
, /* pRealizePalette */
7398 NULL
, /* pRectangle */
7399 NULL
, /* pResetDC */
7400 NULL
, /* pRestoreDC */
7401 NULL
, /* pRoundRect */
7403 NULL
, /* pScaleViewportExt */
7404 NULL
, /* pScaleWindowExt */
7405 NULL
, /* pSelectBitmap */
7406 NULL
, /* pSelectBrush */
7407 NULL
, /* pSelectClipPath */
7408 freetype_SelectFont
, /* pSelectFont */
7409 NULL
, /* pSelectPalette */
7410 NULL
, /* pSelectPen */
7411 NULL
, /* pSetArcDirection */
7412 NULL
, /* pSetBkColor */
7413 NULL
, /* pSetBkMode */
7414 NULL
, /* pSetDCBrushColor */
7415 NULL
, /* pSetDCPenColor */
7416 NULL
, /* pSetDIBColorTable */
7417 NULL
, /* pSetDIBitsToDevice */
7418 NULL
, /* pSetDeviceClipping */
7419 NULL
, /* pSetDeviceGammaRamp */
7420 NULL
, /* pSetLayout */
7421 NULL
, /* pSetMapMode */
7422 NULL
, /* pSetMapperFlags */
7423 NULL
, /* pSetPixel */
7424 NULL
, /* pSetPixelFormat */
7425 NULL
, /* pSetPolyFillMode */
7426 NULL
, /* pSetROP2 */
7427 NULL
, /* pSetRelAbs */
7428 NULL
, /* pSetStretchBltMode */
7429 NULL
, /* pSetTextAlign */
7430 NULL
, /* pSetTextCharacterExtra */
7431 NULL
, /* pSetTextColor */
7432 NULL
, /* pSetTextJustification */
7433 NULL
, /* pSetViewportExt */
7434 NULL
, /* pSetViewportOrg */
7435 NULL
, /* pSetWindowExt */
7436 NULL
, /* pSetWindowOrg */
7437 NULL
, /* pSetWorldTransform */
7438 NULL
, /* pStartDoc */
7439 NULL
, /* pStartPage */
7440 NULL
, /* pStretchBlt */
7441 NULL
, /* pStretchDIBits */
7442 NULL
, /* pStrokeAndFillPath */
7443 NULL
, /* pStrokePath */
7444 NULL
, /* pSwapBuffers */
7445 NULL
, /* pUnrealizePalette */
7446 NULL
, /* pWidenPath */
7447 /* OpenGL not supported */
7450 #else /* HAVE_FREETYPE */
7452 /*************************************************************************/
7454 BOOL
WineEngInit(void)
7458 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7463 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7465 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7469 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7471 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7475 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7477 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7481 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7486 /*************************************************************************
7487 * GetRasterizerCaps (GDI32.@)
7489 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7491 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7493 lprs
->nLanguageID
= 0;
7497 #endif /* HAVE_FREETYPE */