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
;
268 FONTSIGNATURE fs_links
;
270 FT_Fixed font_version
;
273 Bitmap_Size size
; /* set if face is a bitmap */
274 BOOL external
; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily
*family
;
276 /* Cached data for Enum */
277 struct enum_data
*cached_enum_data
;
280 typedef struct tagFamily
{
282 const WCHAR
*FamilyName
;
283 const WCHAR
*EnglishName
;
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
;
357 struct enum_charset_element
{
360 WCHAR name
[LF_FACESIZE
];
363 struct enum_charset_list
{
365 struct enum_charset_element element
[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
372 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list
= LIST_INIT(child_font_list
);
375 static struct list system_links
= LIST_INIT(system_links
);
377 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
379 static struct list font_list
= LIST_INIT(font_list
);
381 struct freetype_physdev
383 struct gdi_physdev dev
;
387 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
389 return (struct freetype_physdev
*)dev
;
392 static const struct gdi_dc_funcs freetype_funcs
;
394 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
395 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
396 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
398 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
399 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
400 'W','i','n','d','o','w','s','\\',
401 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
402 'F','o','n','t','s','\0'};
404 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s',' ','N','T','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
410 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
411 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
412 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
414 static const WCHAR
* const SystemFontValues
[] = {
421 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
422 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
424 /* Interesting and well-known (frequently-assumed!) font names */
425 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
426 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 };
427 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
428 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
429 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
430 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
431 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
432 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
434 static const WCHAR arial
[] = {'A','r','i','a','l',0};
435 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
436 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};
437 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};
438 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
439 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
440 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
441 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
442 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
443 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
445 static const WCHAR
*default_serif_list
[] =
449 bitstream_vera_serif
,
453 static const WCHAR
*default_fixed_list
[] =
457 bitstream_vera_sans_mono
,
461 static const WCHAR
*default_sans_list
[] =
474 typedef struct tagFontSubst
{
480 /* Registry font cache key and value names */
481 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
482 'F','o','n','t','s',0};
483 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
484 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
485 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
486 static const WCHAR face_italic_value
[] = {'I','t','a','l','i','c',0};
487 static const WCHAR face_bold_value
[] = {'B','o','l','d',0};
488 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_external_value
[] = {'E','x','t','e','r','n','a','l',0};
490 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
510 static struct list mappings_list
= LIST_INIT( mappings_list
);
512 static CRITICAL_SECTION freetype_cs
;
513 static CRITICAL_SECTION_DEBUG critsect_debug
=
516 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
517 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback
= FALSE
;
526 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
527 static BOOL
get_outline_text_metrics(GdiFont
*font
);
528 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
530 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * FIXEDFON.FON FixedSys
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
588 GSUB_ScriptRecord ScriptRecord
[1];
594 } GSUB_LangSysRecord
;
599 GSUB_LangSysRecord LangSysRecord
[1];
603 WORD LookupOrder
; /* Reserved */
604 WORD ReqFeatureIndex
;
606 WORD FeatureIndex
[1];
612 } GSUB_FeatureRecord
;
616 GSUB_FeatureRecord FeatureRecord
[1];
620 WORD FeatureParams
; /* Reserved */
622 WORD LookupListIndex
[1];
641 } GSUB_CoverageFormat1
;
646 WORD StartCoverageIndex
;
652 GSUB_RangeRecord RangeRecord
[1];
653 } GSUB_CoverageFormat2
;
656 WORD SubstFormat
; /* = 1 */
659 } GSUB_SingleSubstFormat1
;
662 WORD SubstFormat
; /* = 2 */
666 }GSUB_SingleSubstFormat2
;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
673 static char cached_path
[MAX_PATH
];
674 static const char *wine
= "/Wine", *fonts
= "/Fonts";
676 if(*cached_path
) return cached_path
;
678 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
681 WARN("can't create cached data folder\n");
684 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
687 WARN("can't create cached data path\n");
691 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
693 ERR("Could not create full path\n");
697 strcat(cached_path
, wine
);
699 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
701 WARN("Couldn't mkdir %s\n", cached_path
);
705 strcat(cached_path
, fonts
);
706 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
708 WARN("Couldn't mkdir %s\n", cached_path
);
715 /******************************************************************
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path
)
733 const char *filename
;
737 unsigned int size
, max_size
;
740 TRACE("path %s\n", path
);
742 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
745 WARN("failed to get ref\n");
749 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
756 TRACE("unable to open resource fork\n");
763 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
766 CloseResFile(res_ref
);
770 out_dir
= find_cache_dir();
772 filename
= strrchr(path
, '/');
773 if(!filename
) filename
= path
;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
784 unsigned short *num_faces_ptr
, num_faces
, face
;
787 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
789 fond
= Get1IndResource(fond_res
, idx
);
791 TRACE("got fond resource %d\n", idx
);
794 fam_rec
= *(FamRec
**)fond
;
795 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
796 num_faces
= GET_BE_WORD(*num_faces_ptr
);
798 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
799 TRACE("num faces %04x\n", num_faces
);
800 for(face
= 0; face
< num_faces
; face
++, assoc
++)
803 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
804 unsigned short size
, font_id
;
807 size
= GET_BE_WORD(assoc
->fontSize
);
808 font_id
= GET_BE_WORD(assoc
->fontID
);
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
815 TRACE("trying to load sfnt id %04x\n", font_id
);
816 sfnt
= GetResource(sfnt_res
, font_id
);
819 TRACE("can't get sfnt resource %04x\n", font_id
);
823 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
828 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
830 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
831 if(fd
!= -1 || errno
== EEXIST
)
835 unsigned char *sfnt_data
;
838 sfnt_data
= *(unsigned char**)sfnt
;
839 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
843 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
846 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
848 ret
.array
[ret
.size
++] = output
;
852 WARN("unable to create %s\n", output
);
853 HeapFree(GetProcessHeap(), 0, output
);
856 ReleaseResource(sfnt
);
859 ReleaseResource(fond
);
862 CloseResFile(res_ref
);
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL
is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed
FT_FixedFromFloat(double f
)
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
888 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
892 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
897 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
898 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
900 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
901 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
903 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
905 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
907 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
911 file
= strrchr(face
->file
, '/');
916 if(!strcasecmp(file
, file_nameA
))
918 HeapFree(GetProcessHeap(), 0, file_nameA
);
923 HeapFree(GetProcessHeap(), 0, file_nameA
);
927 static Family
*find_family_from_name(const WCHAR
*name
)
931 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
933 if(!strcmpiW(family
->FamilyName
, name
))
940 static Family
*find_family_from_any_name(const WCHAR
*name
)
944 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
946 if(!strcmpiW(family
->FamilyName
, name
))
948 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
955 static void DumpSubstList(void)
959 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
961 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
962 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
963 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
965 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
966 debugstr_w(psub
->to
.name
));
971 static LPWSTR
strdupW(LPCWSTR p
)
974 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
975 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
980 static LPSTR
strdupA(LPCSTR p
)
983 DWORD len
= (strlen(p
) + 1);
984 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
989 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
994 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
996 if(!strcmpiW(element
->from
.name
, from_name
) &&
997 (element
->from
.charset
== from_charset
||
998 element
->from
.charset
== -1))
1005 #define ADD_FONT_SUBST_FORCE 1
1007 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1009 FontSubst
*from_exist
, *to_exist
;
1011 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1013 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1015 list_remove(&from_exist
->entry
);
1016 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
1017 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
1018 HeapFree(GetProcessHeap(), 0, from_exist
);
1024 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1028 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1029 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1032 list_add_tail(subst_list
, &subst
->entry
);
1037 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1038 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1039 HeapFree(GetProcessHeap(), 0, subst
);
1043 static WCHAR
*towstr(UINT cp
, const char *str
)
1048 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1049 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1050 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1054 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1056 CHAR
*p
= strrchr(str
, ',');
1060 nc
->charset
= strtol(p
+1, NULL
, 10);
1063 nc
->name
= towstr(CP_ACP
, str
);
1066 static void LoadSubstList(void)
1070 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1074 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1075 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1076 &hkey
) == ERROR_SUCCESS
) {
1078 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1079 &valuelen
, &datalen
, NULL
, NULL
);
1081 valuelen
++; /* returned value doesn't include room for '\0' */
1082 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1083 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1087 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1088 &dlen
) == ERROR_SUCCESS
) {
1089 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1091 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1092 split_subst_info(&psub
->from
, value
);
1093 split_subst_info(&psub
->to
, data
);
1095 /* Win 2000 doesn't allow mapping between different charsets
1096 or mapping of DEFAULT_CHARSET */
1097 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1098 psub
->to
.charset
== DEFAULT_CHARSET
) {
1099 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1100 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1101 HeapFree(GetProcessHeap(), 0, psub
);
1103 add_font_subst(&font_subst_list
, psub
, 0);
1105 /* reset dlen and vlen */
1109 HeapFree(GetProcessHeap(), 0, data
);
1110 HeapFree(GetProcessHeap(), 0, value
);
1116 /*****************************************************************
1117 * get_name_table_entry
1119 * Supply the platform, encoding, language and name ids in req
1120 * and if the name exists the function will fill in the string
1121 * and string_len members. The string is owned by FreeType so
1122 * don't free it. Returns TRUE if the name is found else FALSE.
1124 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1127 FT_UInt num_names
, name_index
;
1129 if(FT_IS_SFNT(ft_face
))
1131 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1133 for(name_index
= 0; name_index
< num_names
; name_index
++)
1135 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1137 if((name
.platform_id
== req
->platform_id
) &&
1138 (name
.encoding_id
== req
->encoding_id
) &&
1139 (name
.language_id
== req
->language_id
) &&
1140 (name
.name_id
== req
->name_id
))
1142 req
->string
= name
.string
;
1143 req
->string_len
= name
.string_len
;
1150 req
->string_len
= 0;
1154 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1159 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1160 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1161 name
.language_id
= language_id
;
1162 name
.name_id
= name_id
;
1164 if(get_name_table_entry(ft_face
, &name
))
1168 /* String is not nul terminated and string_len is a byte length. */
1169 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1170 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1172 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1173 ret
[i
] = GET_BE_WORD(*tmp
);
1176 TRACE("Got localised name %s\n", debugstr_w(ret
));
1182 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1185 LONG r
= RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, &needed
);
1186 if(r
!= ERROR_SUCCESS
) return r
;
1187 if(type
!= REG_DWORD
|| needed
!= sizeof(DWORD
)) return ERROR_BAD_CONFIGURATION
;
1188 return RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &needed
);
1191 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1193 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1196 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
)
1199 DWORD num_strikes
, max_strike_key_len
;
1201 /* If we have a File Name key then this is a real font, not just the parent
1202 key of a bunch of non-scalable strikes */
1203 if(RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1207 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1208 face
->cached_enum_data
= NULL
;
1210 face
->file
= HeapAlloc(GetProcessHeap(), 0, needed
);
1211 RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, (BYTE
*)face
->file
, &needed
);
1213 face
->StyleName
= strdupW(face_name
);
1214 face
->family
= family
;
1215 face
->vertical
= (family
->FamilyName
[0] == '@');
1217 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1219 WCHAR
*fullName
= HeapAlloc(GetProcessHeap(), 0, needed
);
1220 RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, (BYTE
*)fullName
, &needed
);
1221 face
->FullName
= fullName
;
1224 face
->FullName
= NULL
;
1226 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1227 reg_load_dword(hkey_face
, face_italic_value
, &italic
);
1228 reg_load_dword(hkey_face
, face_bold_value
, &bold
);
1229 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1230 reg_load_dword(hkey_face
, face_external_value
, (DWORD
*)&face
->external
);
1232 needed
= sizeof(face
->fs
);
1233 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1234 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1236 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1238 face
->scalable
= TRUE
;
1239 memset(&face
->size
, 0, sizeof(face
->size
));
1243 face
->scalable
= FALSE
;
1244 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1245 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1246 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1247 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1248 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1250 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1251 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1252 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1256 if (italic
) face
->ntmFlags
|= NTM_ITALIC
;
1257 if (bold
) face
->ntmFlags
|= NTM_BOLD
;
1258 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1260 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1261 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1262 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1263 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1265 if(!italic
&& !bold
)
1266 list_add_head(&family
->faces
, &face
->entry
);
1268 list_add_tail(&family
->faces
, &face
->entry
);
1270 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1273 /* do we have any bitmap strikes? */
1274 RegQueryInfoKeyW(hkey_face
, NULL
, NULL
, NULL
, &num_strikes
, &max_strike_key_len
, NULL
, NULL
,
1275 NULL
, NULL
, NULL
, NULL
);
1276 if(num_strikes
!= 0)
1278 WCHAR strike_name
[10];
1279 DWORD strike_index
= 0;
1281 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1282 while(RegEnumKeyExW(hkey_face
, strike_index
++, strike_name
, &needed
,
1283 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1286 RegOpenKeyExW(hkey_face
, strike_name
, 0, KEY_ALL_ACCESS
, &hkey_strike
);
1287 load_face(hkey_strike
, face_name
, family
);
1288 RegCloseKey(hkey_strike
);
1289 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1294 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1296 DWORD max_family_key_len
, size
;
1298 DWORD family_index
= 0;
1302 RegQueryInfoKeyW(hkey_font_cache
, NULL
, NULL
, NULL
, NULL
, &max_family_key_len
, NULL
, NULL
,
1303 NULL
, NULL
, NULL
, NULL
);
1304 family_name
= HeapAlloc(GetProcessHeap(), 0, (max_family_key_len
+ 1) * sizeof(WCHAR
));
1306 size
= max_family_key_len
+ 1;
1307 while(RegEnumKeyExW(hkey_font_cache
, family_index
++, family_name
, &size
,
1308 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1310 WCHAR
*english_family
= NULL
;
1311 DWORD face_index
= 0;
1313 DWORD max_face_key_len
;
1315 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1316 TRACE("opened family key %s\n", debugstr_w(family_name
));
1317 if(RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, NULL
, &size
) == ERROR_SUCCESS
)
1319 english_family
= HeapAlloc(GetProcessHeap(), 0, size
);
1320 RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)english_family
, &size
);
1323 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1324 family
->FamilyName
= strdupW(family_name
);
1325 family
->EnglishName
= english_family
;
1326 list_init(&family
->faces
);
1327 list_add_tail(&font_list
, &family
->entry
);
1331 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1332 subst
->from
.name
= strdupW(english_family
);
1333 subst
->from
.charset
= -1;
1334 subst
->to
.name
= strdupW(family_name
);
1335 subst
->to
.charset
= -1;
1336 add_font_subst(&font_subst_list
, subst
, 0);
1339 RegQueryInfoKeyW(hkey_family
, NULL
, NULL
, NULL
, NULL
, &max_face_key_len
, NULL
, NULL
,
1340 NULL
, NULL
, NULL
, NULL
);
1342 face_name
= HeapAlloc(GetProcessHeap(), 0, (max_face_key_len
+ 1) * sizeof(WCHAR
));
1343 size
= max_face_key_len
+ 1;
1344 while(RegEnumKeyExW(hkey_family
, face_index
++, face_name
, &size
,
1345 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1349 RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
);
1350 load_face(hkey_face
, face_name
, family
);
1351 RegCloseKey(hkey_face
);
1352 size
= max_face_key_len
+ 1;
1354 HeapFree(GetProcessHeap(), 0, face_name
);
1355 RegCloseKey(hkey_family
);
1356 size
= max_family_key_len
+ 1;
1359 HeapFree(GetProcessHeap(), 0, family_name
);
1362 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1365 HKEY hkey_wine_fonts
;
1367 /* We don't want to create the fonts key as volatile, so open this first */
1368 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1369 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1370 if(ret
!= ERROR_SUCCESS
)
1372 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1376 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1377 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1378 RegCloseKey(hkey_wine_fonts
);
1382 static void add_face_to_cache(Face
*face
)
1384 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1385 WCHAR
*face_key_name
;
1387 create_font_cache_key(&hkey_font_cache
, NULL
);
1389 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1390 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1391 if(face
->family
->EnglishName
)
1392 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1393 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1396 face_key_name
= face
->StyleName
;
1399 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1400 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1401 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1403 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1406 HeapFree(GetProcessHeap(), 0, face_key_name
);
1408 RegSetValueExA(hkey_face
, "File Name", 0, REG_BINARY
, (BYTE
*)face
->file
, strlen(face
->file
) + 1);
1410 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1411 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1413 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1414 reg_save_dword(hkey_face
, face_italic_value
, (face
->ntmFlags
& NTM_ITALIC
) != 0);
1415 reg_save_dword(hkey_face
, face_bold_value
, (face
->ntmFlags
& NTM_BOLD
) != 0);
1416 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1417 reg_save_dword(hkey_face
, face_external_value
, face
->external
);
1419 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1423 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1424 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1425 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1426 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1427 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1428 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1430 RegCloseKey(hkey_face
);
1431 RegCloseKey(hkey_family
);
1432 RegCloseKey(hkey_font_cache
);
1435 static inline int TestStyles(DWORD flags
, DWORD styles
)
1437 return (flags
& styles
) == styles
;
1440 static int StyleOrdering(Face
*face
)
1442 if (TestStyles(face
->ntmFlags
, NTM_BOLD
| NTM_ITALIC
))
1444 if (TestStyles(face
->ntmFlags
, NTM_ITALIC
))
1446 if (TestStyles(face
->ntmFlags
, NTM_BOLD
))
1448 if (TestStyles(face
->ntmFlags
, NTM_REGULAR
))
1451 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1452 debugstr_w(face
->family
->FamilyName
),
1453 debugstr_w(face
->StyleName
),
1459 /* Add a style of face to a font family using an ordering of the list such
1460 that regular fonts come before bold and italic, and single styles come
1461 before compound styles. */
1462 static void AddFaceToFamily(Face
*face
, Family
*family
)
1466 LIST_FOR_EACH( entry
, &family
->faces
)
1468 Face
*ent
= LIST_ENTRY(entry
, Face
, entry
);
1469 if (StyleOrdering(face
) < StyleOrdering(ent
)) break;
1471 list_add_before( entry
, &face
->entry
);
1474 static WCHAR
*prepend_at(WCHAR
*family
)
1481 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1483 strcpyW(str
+ 1, family
);
1484 HeapFree(GetProcessHeap(), 0, family
);
1488 #define ADDFONT_EXTERNAL_FONT 0x01
1489 #define ADDFONT_FORCE_BITMAP 0x02
1490 #define ADDFONT_ADD_TO_CACHE 0x04
1492 static void AddFaceToList(FT_Face ft_face
, char *fake_family
, const char *file
, void *font_data_ptr
, DWORD font_data_size
, FT_Long face_index
, DWORD flags
, BOOL vertical
)
1501 WCHAR
*english_family
, *localised_family
;
1503 struct list
*face_elem_ptr
;
1504 FT_WinFNT_HeaderRec winfnt_header
;
1505 int internal_leading
;
1507 My_FT_Bitmap_Size
*size
= NULL
;
1510 if(!FT_IS_SCALABLE(ft_face
))
1511 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1515 english_family
= towstr(CP_ACP
, fake_family
);
1516 localised_family
= NULL
;
1520 english_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1521 if (!english_family
)
1522 english_family
= towstr(CP_ACP
, ft_face
->family_name
);
1524 localised_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID());
1525 if (localised_family
&& !strcmpiW(localised_family
, english_family
))
1527 HeapFree(GetProcessHeap(), 0, localised_family
);
1528 localised_family
= NULL
;
1534 english_family
= prepend_at(english_family
);
1535 localised_family
= prepend_at(localised_family
);
1538 family
= find_family_from_name(localised_family
? localised_family
: english_family
);
1540 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1541 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1542 family
->EnglishName
= localised_family
? strdupW(english_family
) : NULL
;
1543 list_init(&family
->faces
);
1544 list_add_tail(&font_list
, &family
->entry
);
1546 if(localised_family
) {
1547 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1548 subst
->from
.name
= strdupW(english_family
);
1549 subst
->from
.charset
= -1;
1550 subst
->to
.name
= strdupW(localised_family
);
1551 subst
->to
.charset
= -1;
1552 add_font_subst(&font_subst_list
, subst
, 0);
1555 HeapFree(GetProcessHeap(), 0, localised_family
);
1556 HeapFree(GetProcessHeap(), 0, english_family
);
1558 StyleW
= towstr(CP_ACP
, ft_face
->style_name
);
1560 internal_leading
= 0;
1561 memset(&fs
, 0, sizeof(fs
));
1563 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1565 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1566 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1567 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1568 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1569 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1570 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1571 if(pOS2
->version
== 0) {
1574 if(pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1575 fs
.fsCsb
[0] |= FS_LATIN1
;
1577 fs
.fsCsb
[0] |= FS_SYMBOL
;
1580 else if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1582 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1583 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1584 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1586 internal_leading
= winfnt_header
.internal_leading
;
1589 pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
);
1590 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1591 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1592 if(!strcmpiW(face
->StyleName
, StyleW
) &&
1593 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1594 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1595 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1596 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1599 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1600 HeapFree(GetProcessHeap(), 0, StyleW
);
1603 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1604 TRACE("Original font is newer so skipping this one\n");
1605 HeapFree(GetProcessHeap(), 0, StyleW
);
1608 TRACE("Replacing original with this one\n");
1609 list_remove(&face
->entry
);
1610 HeapFree(GetProcessHeap(), 0, face
->file
);
1611 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1612 HeapFree(GetProcessHeap(), 0, face
->FullName
);
1613 HeapFree(GetProcessHeap(), 0, face
);
1618 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1619 face
->cached_enum_data
= NULL
;
1620 face
->StyleName
= StyleW
;
1621 face
->FullName
= get_face_name(ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1624 face
->file
= strdupA(file
);
1625 face
->font_data_ptr
= NULL
;
1626 face
->font_data_size
= 0;
1631 face
->font_data_ptr
= font_data_ptr
;
1632 face
->font_data_size
= font_data_size
;
1634 face
->face_index
= face_index
;
1636 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
1637 face
->ntmFlags
|= NTM_ITALIC
;
1638 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
1639 face
->ntmFlags
|= NTM_BOLD
;
1640 if (face
->ntmFlags
== 0) face
->ntmFlags
= NTM_REGULAR
;
1641 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1642 face
->family
= family
;
1643 face
->vertical
= vertical
;
1644 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1646 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1648 if(FT_IS_SCALABLE(ft_face
)) {
1649 memset(&face
->size
, 0, sizeof(face
->size
));
1650 face
->scalable
= TRUE
;
1652 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1653 size
->height
, size
->width
, size
->size
>> 6,
1654 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1655 face
->size
.height
= size
->height
;
1656 face
->size
.width
= size
->width
;
1657 face
->size
.size
= size
->size
;
1658 face
->size
.x_ppem
= size
->x_ppem
;
1659 face
->size
.y_ppem
= size
->y_ppem
;
1660 face
->size
.internal_leading
= internal_leading
;
1661 face
->scalable
= FALSE
;
1664 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1666 if (!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
1668 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file
), font_data_ptr
);
1669 face
->ntmFlags
|= NTM_PS_OPENTYPE
;
1672 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1673 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1674 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1675 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1677 if(face
->fs
.fsCsb
[0] == 0)
1681 /* let's see if we can find any interesting cmaps */
1682 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1683 switch(ft_face
->charmaps
[i
]->encoding
) {
1684 case FT_ENCODING_UNICODE
:
1685 case FT_ENCODING_APPLE_ROMAN
:
1686 face
->fs
.fsCsb
[0] |= FS_LATIN1
;
1688 case FT_ENCODING_MS_SYMBOL
:
1689 face
->fs
.fsCsb
[0] |= FS_SYMBOL
;
1697 if(flags
& ADDFONT_ADD_TO_CACHE
)
1698 add_face_to_cache(face
);
1700 AddFaceToFamily(face
, family
);
1702 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1704 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1705 debugstr_w(StyleW
));
1708 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1712 TT_Header
*pHeader
= NULL
;
1713 WCHAR
*localised_family
;
1715 FT_Long face_index
= 0, num_faces
;
1718 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1719 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1721 #ifdef HAVE_CARBON_CARBON_H
1722 if(file
&& !fake_family
)
1724 char **mac_list
= expand_mac_font(file
);
1727 BOOL had_one
= FALSE
;
1729 for(cursor
= mac_list
; *cursor
; cursor
++)
1732 AddFontToList(*cursor
, NULL
, 0, NULL
, NULL
, flags
);
1733 HeapFree(GetProcessHeap(), 0, *cursor
);
1735 HeapFree(GetProcessHeap(), 0, mac_list
);
1740 #endif /* HAVE_CARBON_CARBON_H */
1745 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1746 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1749 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1750 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1754 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1758 if(!FT_IS_SFNT(ft_face
) && (FT_IS_SCALABLE(ft_face
) || !(flags
& ADDFONT_FORCE_BITMAP
))) { /* for now we'll accept TT/OT or bitmap fonts*/
1759 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1760 pFT_Done_Face(ft_face
);
1764 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1765 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1766 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1767 pFT_Done_Face(ft_face
);
1771 if(FT_IS_SFNT(ft_face
))
1773 if(!(pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
)) ||
1774 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1775 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))
1777 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1778 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1779 pFT_Done_Face(ft_face
);
1783 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1784 we don't want to load these. */
1785 if(!memcmp(pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
)))
1789 if(!pFT_Load_Sfnt_Table(ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1791 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1792 pFT_Done_Face(ft_face
);
1798 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1799 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1800 pFT_Done_Face(ft_face
);
1804 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1806 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1807 pFT_Done_Face(ft_face
);
1813 localised_family
= get_face_name(ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID());
1814 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1816 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1817 HeapFree(GetProcessHeap(), 0, localised_family
);
1818 num_faces
= ft_face
->num_faces
;
1819 pFT_Done_Face(ft_face
);
1822 HeapFree(GetProcessHeap(), 0, localised_family
);
1825 AddFaceToList(ft_face
, fake_family
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1828 if (FT_HAS_VERTICAL(ft_face
))
1830 AddFaceToList(ft_face
, fake_family
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1834 num_faces
= ft_face
->num_faces
;
1835 pFT_Done_Face(ft_face
);
1836 } while(num_faces
> ++face_index
);
1840 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
1842 return AddFontToList(file
, NULL
, 0, fake_family
, target_family
, flags
);
1845 static void DumpFontList(void)
1849 struct list
*family_elem_ptr
, *face_elem_ptr
;
1851 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1852 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1853 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1854 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1855 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1856 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1858 TRACE(" %d", face
->size
.height
);
1865 /***********************************************************
1866 * The replacement list is a way to map an entire font
1867 * family onto another family. For example adding
1869 * [HKCU\Software\Wine\Fonts\Replacements]
1870 * "Wingdings"="Winedings"
1872 * would enumerate the Winedings font both as Winedings and
1873 * Wingdings. However if a real Wingdings font is present the
1874 * replacement does not take place.
1877 static void LoadReplaceList(void)
1880 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1885 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1886 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1888 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1889 &valuelen
, &datalen
, NULL
, NULL
);
1891 valuelen
++; /* returned value doesn't include room for '\0' */
1892 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1893 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1897 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1898 &dlen
) == ERROR_SUCCESS
) {
1899 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1900 /* "NewName"="Oldname" */
1901 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1903 if(!find_family_from_any_name(value
))
1905 /* Find the old family and hence all of the font files
1907 const Family
* const family
= find_family_from_any_name(data
);
1910 const struct list
*face_elem_ptr
;
1911 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1912 const Face
* const face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1913 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1914 debugstr_w(face
->StyleName
), familyA
);
1915 /* Now add a new entry with the new family name */
1916 AddFontToList(face
->file
, face
->font_data_ptr
, face
->font_data_size
,
1917 familyA
, family
->FamilyName
,
1918 ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1922 /* reset dlen and vlen */
1926 HeapFree(GetProcessHeap(), 0, data
);
1927 HeapFree(GetProcessHeap(), 0, value
);
1932 static const WCHAR
*font_links_list
[] =
1934 Lucida_Sans_Unicode
,
1935 Microsoft_Sans_Serif
,
1939 static const struct font_links_defaults_list
1941 /* Keyed off substitution for "MS Shell Dlg" */
1942 const WCHAR
*shelldlg
;
1943 /* Maximum of four substitutes, plus terminating NULL pointer */
1944 const WCHAR
*substitutes
[5];
1945 } font_links_defaults_list
[] =
1947 /* Non East-Asian */
1948 { Tahoma
, /* FIXME unverified ordering */
1949 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
1951 /* Below lists are courtesy of
1952 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1956 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
1958 /* Chinese Simplified */
1960 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
1964 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
1966 /* Chinese Traditional */
1968 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
1973 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
1986 SYSTEM_LINKS
*font_link
;
1987 BOOL existing
= FALSE
;
1989 memset(&fs
, 0, sizeof(fs
));
1990 psub
= get_font_subst(&font_subst_list
, name
, -1);
1991 /* Don't store fonts that are only substitutes for other fonts */
1994 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
1998 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2000 if(!strcmpiW(font_link
->font_name
, name
))
2009 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2010 font_link
->font_name
= strdupW(name
);
2011 list_init(&font_link
->links
);
2014 for (i
= 0; values
[i
] != NULL
; i
++)
2016 CHILD_FONT
*child_font
;
2019 if (!strcmpiW(name
,value
))
2021 psub
= get_font_subst(&font_subst_list
, value
, -1);
2023 value
= psub
->to
.name
;
2024 family
= find_family_from_name(value
);
2028 /* Use first extant filename for this Family */
2029 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2033 file
= strrchr(face
->file
, '/');
2042 fileW
= towstr(CP_UNIXCP
, file
);
2044 face
= find_face_from_filename(fileW
, value
);
2047 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2051 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2052 child_font
->face
= face
;
2053 child_font
->font
= NULL
;
2054 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2055 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2056 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2057 list_add_tail(&font_link
->links
, &child_font
->entry
);
2059 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2060 HeapFree(GetProcessHeap(), 0, fileW
);
2063 family
= find_family_from_name(font_link
->font_name
);
2066 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2068 face
->fs_links
= fs
;
2072 list_add_tail(&system_links
, &font_link
->entry
);
2077 /*************************************************************
2080 static BOOL
init_system_links(void)
2084 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2085 WCHAR
*value
, *data
;
2086 WCHAR
*entry
, *next
;
2087 SYSTEM_LINKS
*font_link
, *system_font_link
;
2088 CHILD_FONT
*child_font
;
2089 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2090 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2091 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2098 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2100 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2101 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2102 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2103 val_len
= max_val
+ 1;
2104 data_len
= max_data
;
2106 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2108 memset(&fs
, 0, sizeof(fs
));
2109 psub
= get_font_subst(&font_subst_list
, value
, -1);
2110 /* Don't store fonts that are only substitutes for other fonts */
2113 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2116 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2117 font_link
->font_name
= strdupW(value
);
2118 list_init(&font_link
->links
);
2119 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2122 CHILD_FONT
*child_font
;
2124 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2126 next
= entry
+ strlenW(entry
) + 1;
2128 face_name
= strchrW(entry
, ',');
2132 while(isspaceW(*face_name
))
2135 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2137 face_name
= psub
->to
.name
;
2139 face
= find_face_from_filename(entry
, face_name
);
2142 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2146 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2147 child_font
->face
= face
;
2148 child_font
->font
= NULL
;
2149 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2150 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2151 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2152 list_add_tail(&font_link
->links
, &child_font
->entry
);
2154 family
= find_family_from_name(font_link
->font_name
);
2157 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2159 face
->fs_links
= fs
;
2162 list_add_tail(&system_links
, &font_link
->entry
);
2164 val_len
= max_val
+ 1;
2165 data_len
= max_data
;
2168 HeapFree(GetProcessHeap(), 0, value
);
2169 HeapFree(GetProcessHeap(), 0, data
);
2174 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2176 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2180 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2182 const FontSubst
*psub2
;
2183 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2185 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2187 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2188 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2190 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2191 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2193 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2195 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2201 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2204 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2205 system_font_link
->font_name
= strdupW(System
);
2206 list_init(&system_font_link
->links
);
2208 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2211 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2212 child_font
->face
= face
;
2213 child_font
->font
= NULL
;
2214 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2215 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2217 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2219 if(!strcmpiW(font_link
->font_name
, Tahoma
))
2221 CHILD_FONT
*font_link_entry
;
2222 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2224 CHILD_FONT
*new_child
;
2225 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2226 new_child
->face
= font_link_entry
->face
;
2227 new_child
->font
= NULL
;
2228 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2233 list_add_tail(&system_links
, &system_font_link
->entry
);
2237 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2240 struct dirent
*dent
;
2241 char path
[MAX_PATH
];
2243 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2245 dir
= opendir(dirname
);
2247 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2250 while((dent
= readdir(dir
)) != NULL
) {
2251 struct stat statbuf
;
2253 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2256 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2258 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2260 if(stat(path
, &statbuf
) == -1)
2262 WARN("Can't stat %s\n", debugstr_a(path
));
2265 if(S_ISDIR(statbuf
.st_mode
))
2266 ReadFontDir(path
, external_fonts
);
2269 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2270 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2271 AddFontFileToList(path
, NULL
, NULL
, addfont_flags
);
2278 static void load_fontconfig_fonts(void)
2280 #ifdef SONAME_LIBFONTCONFIG
2281 void *fc_handle
= NULL
;
2290 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2292 TRACE("Wine cannot find the fontconfig library (%s).\n",
2293 SONAME_LIBFONTCONFIG
);
2296 #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;}
2297 LOAD_FUNCPTR(FcConfigGetCurrent
);
2298 LOAD_FUNCPTR(FcFontList
);
2299 LOAD_FUNCPTR(FcFontSetDestroy
);
2300 LOAD_FUNCPTR(FcInit
);
2301 LOAD_FUNCPTR(FcObjectSetAdd
);
2302 LOAD_FUNCPTR(FcObjectSetCreate
);
2303 LOAD_FUNCPTR(FcObjectSetDestroy
);
2304 LOAD_FUNCPTR(FcPatternCreate
);
2305 LOAD_FUNCPTR(FcPatternDestroy
);
2306 LOAD_FUNCPTR(FcPatternGetBool
);
2307 LOAD_FUNCPTR(FcPatternGetString
);
2310 if(!pFcInit()) return;
2312 config
= pFcConfigGetCurrent();
2313 pat
= pFcPatternCreate();
2314 os
= pFcObjectSetCreate();
2315 pFcObjectSetAdd(os
, FC_FILE
);
2316 pFcObjectSetAdd(os
, FC_SCALABLE
);
2317 fontset
= pFcFontList(config
, pat
, os
);
2318 if(!fontset
) return;
2319 for(i
= 0; i
< fontset
->nfont
; i
++) {
2322 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2324 TRACE("fontconfig: %s\n", file
);
2326 /* We're just interested in OT/TT fonts for now, so this hack just
2327 picks up the scalable fonts without extensions .pf[ab] to save time
2328 loading every other font */
2330 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2332 TRACE("not scalable\n");
2336 len
= strlen( file
);
2337 if(len
< 4) continue;
2338 ext
= &file
[ len
- 3 ];
2339 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2340 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2342 pFcFontSetDestroy(fontset
);
2343 pFcObjectSetDestroy(os
);
2344 pFcPatternDestroy(pat
);
2350 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2353 const char *data_dir
= wine_get_data_dir();
2355 if (!data_dir
) data_dir
= wine_get_build_dir();
2362 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2364 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2366 strcpy(unix_name
, data_dir
);
2367 strcat(unix_name
, "/fonts/");
2369 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2371 EnterCriticalSection( &freetype_cs
);
2372 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2373 LeaveCriticalSection( &freetype_cs
);
2374 HeapFree(GetProcessHeap(), 0, unix_name
);
2379 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2381 static const WCHAR slashW
[] = {'\\','\0'};
2383 WCHAR windowsdir
[MAX_PATH
];
2386 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2387 strcatW(windowsdir
, fontsW
);
2388 strcatW(windowsdir
, slashW
);
2389 strcatW(windowsdir
, file
);
2390 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2391 EnterCriticalSection( &freetype_cs
);
2392 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2393 LeaveCriticalSection( &freetype_cs
);
2394 HeapFree(GetProcessHeap(), 0, unixname
);
2399 static void load_system_fonts(void)
2402 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2403 const WCHAR
* const *value
;
2405 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2408 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2409 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2410 strcatW(windowsdir
, fontsW
);
2411 for(value
= SystemFontValues
; *value
; value
++) {
2412 dlen
= sizeof(data
);
2413 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2417 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2418 if((unixname
= wine_get_unix_file_name(pathW
))) {
2419 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2420 HeapFree(GetProcessHeap(), 0, unixname
);
2423 load_font_from_data_dir(data
);
2430 /*************************************************************
2432 * This adds registry entries for any externally loaded fonts
2433 * (fonts from fontconfig or FontDirs). It also deletes entries
2434 * of no longer existing fonts.
2437 static void update_reg_entries(void)
2439 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2444 struct list
*family_elem_ptr
, *face_elem_ptr
;
2446 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2447 static const WCHAR spaceW
[] = {' ', '\0'};
2450 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2451 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2452 ERR("Can't create Windows font reg key\n");
2456 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2457 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2458 ERR("Can't create Windows font reg key\n");
2462 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2463 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2464 ERR("Can't create external font reg key\n");
2468 /* enumerate the fonts and add external ones to the two keys */
2470 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2471 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2472 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2473 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2474 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2475 if(!face
->external
) continue;
2477 if (!(face
->ntmFlags
& NTM_REGULAR
))
2478 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2479 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2480 strcpyW(valueW
, family
->FamilyName
);
2481 if(len
!= len_fam
) {
2482 strcatW(valueW
, spaceW
);
2483 strcatW(valueW
, face
->StyleName
);
2485 strcatW(valueW
, TrueType
);
2487 file
= wine_get_dos_file_name(face
->file
);
2489 len
= strlenW(file
) + 1;
2492 if((path
= strrchr(face
->file
, '/')) == NULL
)
2496 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2498 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2499 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2501 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2502 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2503 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2505 HeapFree(GetProcessHeap(), 0, file
);
2506 HeapFree(GetProcessHeap(), 0, valueW
);
2510 if(external_key
) RegCloseKey(external_key
);
2511 if(win9x_key
) RegCloseKey(win9x_key
);
2512 if(winnt_key
) RegCloseKey(winnt_key
);
2516 static void delete_external_font_keys(void)
2518 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2519 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2523 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2524 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2525 ERR("Can't create Windows font reg key\n");
2529 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2530 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2531 ERR("Can't create Windows font reg key\n");
2535 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2536 ERR("Can't create external font reg key\n");
2540 /* Delete all external fonts added last time */
2542 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2543 &valuelen
, &datalen
, NULL
, NULL
);
2544 valuelen
++; /* returned value doesn't include room for '\0' */
2545 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2546 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2548 dlen
= datalen
* sizeof(WCHAR
);
2551 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2552 &dlen
) == ERROR_SUCCESS
) {
2554 RegDeleteValueW(winnt_key
, valueW
);
2555 RegDeleteValueW(win9x_key
, valueW
);
2556 /* reset dlen and vlen */
2560 HeapFree(GetProcessHeap(), 0, data
);
2561 HeapFree(GetProcessHeap(), 0, valueW
);
2563 /* Delete the old external fonts key */
2564 RegCloseKey(external_key
);
2565 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2568 if(win9x_key
) RegCloseKey(win9x_key
);
2569 if(winnt_key
) RegCloseKey(winnt_key
);
2572 /*************************************************************
2573 * WineEngAddFontResourceEx
2576 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2582 if (ft_handle
) /* do it only if we have freetype up and running */
2587 FIXME("Ignoring flags %x\n", flags
);
2589 if((unixname
= wine_get_unix_file_name(file
)))
2591 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2593 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2594 EnterCriticalSection( &freetype_cs
);
2595 ret
= AddFontFileToList(unixname
, NULL
, NULL
, addfont_flags
);
2596 LeaveCriticalSection( &freetype_cs
);
2597 HeapFree(GetProcessHeap(), 0, unixname
);
2599 if (!ret
&& !strchrW(file
, '\\')) {
2600 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2601 ret
= load_font_from_winfonts_dir(file
);
2603 /* Try in datadir/fonts (or builddir/fonts),
2604 * needed for Magic the Gathering Online
2606 ret
= load_font_from_data_dir(file
);
2613 /*************************************************************
2614 * WineEngAddFontMemResourceEx
2617 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2621 if (ft_handle
) /* do it only if we have freetype up and running */
2623 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2625 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2626 memcpy(pFontCopy
, pbFont
, cbFont
);
2628 EnterCriticalSection( &freetype_cs
);
2629 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2630 LeaveCriticalSection( &freetype_cs
);
2634 TRACE("AddFontToList failed\n");
2635 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2638 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2639 * For now return something unique but quite random
2641 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2642 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2649 /*************************************************************
2650 * WineEngRemoveFontResourceEx
2653 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2656 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2660 static const struct nls_update_font_list
2662 UINT ansi_cp
, oem_cp
;
2663 const char *oem
, *fixed
, *system
;
2664 const char *courier
, *serif
, *small
, *sserif
;
2665 /* these are for font substitutes */
2666 const char *shelldlg
, *tmsrmn
;
2667 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2671 const char *from
, *to
;
2672 } arial_0
, courier_new_0
, times_new_roman_0
;
2673 } nls_update_font_list
[] =
2675 /* Latin 1 (United States) */
2676 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2677 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2678 "Tahoma","Times New Roman",
2679 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2682 /* Latin 1 (Multilingual) */
2683 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2684 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2685 "Tahoma","Times New Roman", /* FIXME unverified */
2686 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2689 /* Eastern Europe */
2690 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2691 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2692 "Tahoma","Times New Roman", /* FIXME unverified */
2693 "Fixedsys,238", "System,238",
2694 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2695 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2696 { "Arial CE,0", "Arial,238" },
2697 { "Courier New CE,0", "Courier New,238" },
2698 { "Times New Roman CE,0", "Times New Roman,238" }
2701 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2702 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2703 "Tahoma","Times New Roman", /* FIXME unverified */
2704 "Fixedsys,204", "System,204",
2705 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2706 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2707 { "Arial Cyr,0", "Arial,204" },
2708 { "Courier New Cyr,0", "Courier New,204" },
2709 { "Times New Roman Cyr,0", "Times New Roman,204" }
2712 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2713 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2714 "Tahoma","Times New Roman", /* FIXME unverified */
2715 "Fixedsys,161", "System,161",
2716 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2717 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2718 { "Arial Greek,0", "Arial,161" },
2719 { "Courier New Greek,0", "Courier New,161" },
2720 { "Times New Roman Greek,0", "Times New Roman,161" }
2723 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2724 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2725 "Tahoma","Times New Roman", /* FIXME unverified */
2726 "Fixedsys,162", "System,162",
2727 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2728 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2729 { "Arial Tur,0", "Arial,162" },
2730 { "Courier New Tur,0", "Courier New,162" },
2731 { "Times New Roman Tur,0", "Times New Roman,162" }
2734 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2735 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2736 "Tahoma","Times New Roman", /* FIXME unverified */
2737 "Fixedsys,177", "System,177",
2738 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2739 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2743 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2744 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2745 "Tahoma","Times New Roman", /* FIXME unverified */
2746 "Fixedsys,178", "System,178",
2747 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2748 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2752 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2753 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2754 "Tahoma","Times New Roman", /* FIXME unverified */
2755 "Fixedsys,186", "System,186",
2756 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2757 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2758 { "Arial Baltic,0", "Arial,186" },
2759 { "Courier New Baltic,0", "Courier New,186" },
2760 { "Times New Roman Baltic,0", "Times New Roman,186" }
2763 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2764 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2765 "Tahoma","Times New Roman", /* FIXME unverified */
2766 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2770 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2771 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2772 "Tahoma","Times New Roman", /* FIXME unverified */
2773 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2777 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2778 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2779 "MS UI Gothic","MS Serif",
2780 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2783 /* Chinese Simplified */
2784 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2785 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2786 "SimSun", "NSimSun",
2787 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2791 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2792 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2794 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2797 /* Chinese Traditional */
2798 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2799 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2800 "PMingLiU", "MingLiU",
2801 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2806 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2808 return ( ansi_cp
== 932 /* CP932 for Japanese */
2809 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2810 || ansi_cp
== 949 /* CP949 for Korean */
2811 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2814 static inline HKEY
create_fonts_NT_registry_key(void)
2818 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2819 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2823 static inline HKEY
create_fonts_9x_registry_key(void)
2827 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2828 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2832 static inline HKEY
create_config_fonts_registry_key(void)
2836 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2837 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2841 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2843 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2844 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2845 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2846 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2849 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2852 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2854 RegDeleteValueA(hkey
, name
);
2857 static void update_font_info(void)
2859 char buf
[40], cpbuf
[40];
2862 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2865 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2868 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2869 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2870 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2871 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2872 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2874 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2875 if (is_dbcs_ansi_cp(ansi_cp
))
2876 use_default_fallback
= TRUE
;
2879 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2881 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2886 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2888 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2890 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2893 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2897 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2898 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2900 hkey
= create_config_fonts_registry_key();
2901 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2902 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2903 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2906 hkey
= create_fonts_NT_registry_key();
2907 add_font_list(hkey
, &nls_update_font_list
[i
]);
2910 hkey
= create_fonts_9x_registry_key();
2911 add_font_list(hkey
, &nls_update_font_list
[i
]);
2914 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2916 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2917 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2918 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2919 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2921 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2922 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2923 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2924 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2925 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2926 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2927 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2928 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2930 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2931 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2932 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2940 /* Delete the FontSubstitutes from other locales */
2941 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2943 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2944 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2945 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2951 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2954 static BOOL
init_freetype(void)
2956 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2959 "Wine cannot find the FreeType font library. To enable Wine to\n"
2960 "use TrueType fonts please install a version of FreeType greater than\n"
2961 "or equal to 2.0.5.\n"
2962 "http://www.freetype.org\n");
2966 #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;}
2968 LOAD_FUNCPTR(FT_Done_Face
)
2969 LOAD_FUNCPTR(FT_Get_Char_Index
)
2970 LOAD_FUNCPTR(FT_Get_First_Char
)
2971 LOAD_FUNCPTR(FT_Get_Module
)
2972 LOAD_FUNCPTR(FT_Get_Next_Char
)
2973 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2974 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2975 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2976 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
2977 LOAD_FUNCPTR(FT_Init_FreeType
)
2978 LOAD_FUNCPTR(FT_Library_Version
)
2979 LOAD_FUNCPTR(FT_Load_Glyph
)
2980 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
2981 LOAD_FUNCPTR(FT_Matrix_Multiply
)
2982 #ifndef FT_MULFIX_INLINED
2983 LOAD_FUNCPTR(FT_MulFix
)
2985 LOAD_FUNCPTR(FT_New_Face
)
2986 LOAD_FUNCPTR(FT_New_Memory_Face
)
2987 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
2988 LOAD_FUNCPTR(FT_Outline_Transform
)
2989 LOAD_FUNCPTR(FT_Outline_Translate
)
2990 LOAD_FUNCPTR(FT_Render_Glyph
)
2991 LOAD_FUNCPTR(FT_Select_Charmap
)
2992 LOAD_FUNCPTR(FT_Set_Charmap
)
2993 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
2994 LOAD_FUNCPTR(FT_Vector_Transform
)
2995 LOAD_FUNCPTR(FT_Vector_Unit
)
2997 /* Don't warn if these ones are missing */
2998 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
2999 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3000 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3003 if(pFT_Init_FreeType(&library
) != 0) {
3004 ERR("Can't init FreeType library\n");
3005 wine_dlclose(ft_handle
, NULL
, 0);
3009 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3011 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3012 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3013 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3014 ((FT_Version
.patch
) & 0x0000ff);
3016 font_driver
= &freetype_funcs
;
3021 "Wine cannot find certain functions that it needs inside the FreeType\n"
3022 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3023 "FreeType to at least version 2.1.4.\n"
3024 "http://www.freetype.org\n");
3025 wine_dlclose(ft_handle
, NULL
, 0);
3030 static void init_font_list(void)
3032 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3033 static const WCHAR pathW
[] = {'P','a','t','h',0};
3035 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3036 WCHAR windowsdir
[MAX_PATH
];
3039 const char *data_dir
;
3041 delete_external_font_keys();
3043 /* load the system bitmap fonts */
3044 load_system_fonts();
3046 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3047 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3048 strcatW(windowsdir
, fontsW
);
3049 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3051 ReadFontDir(unixname
, FALSE
);
3052 HeapFree(GetProcessHeap(), 0, unixname
);
3055 /* load the system truetype fonts */
3056 data_dir
= wine_get_data_dir();
3057 if (!data_dir
) data_dir
= wine_get_build_dir();
3058 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3060 strcpy(unixname
, data_dir
);
3061 strcat(unixname
, "/fonts/");
3062 ReadFontDir(unixname
, TRUE
);
3063 HeapFree(GetProcessHeap(), 0, unixname
);
3066 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3067 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3068 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3070 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3071 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3072 &hkey
) == ERROR_SUCCESS
)
3074 LPWSTR data
, valueW
;
3075 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3076 &valuelen
, &datalen
, NULL
, NULL
);
3078 valuelen
++; /* returned value doesn't include room for '\0' */
3079 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3080 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3083 dlen
= datalen
* sizeof(WCHAR
);
3085 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3086 &dlen
) == ERROR_SUCCESS
)
3088 if(data
[0] && (data
[1] == ':'))
3090 if((unixname
= wine_get_unix_file_name(data
)))
3092 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3093 HeapFree(GetProcessHeap(), 0, unixname
);
3096 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3098 WCHAR pathW
[MAX_PATH
];
3099 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3102 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3103 if((unixname
= wine_get_unix_file_name(pathW
)))
3105 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3106 HeapFree(GetProcessHeap(), 0, unixname
);
3109 load_font_from_data_dir(data
);
3111 /* reset dlen and vlen */
3116 HeapFree(GetProcessHeap(), 0, data
);
3117 HeapFree(GetProcessHeap(), 0, valueW
);
3121 load_fontconfig_fonts();
3123 /* then look in any directories that we've specified in the config file */
3124 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3125 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3131 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3133 len
+= sizeof(WCHAR
);
3134 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3135 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3137 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3138 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3139 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3140 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3144 LPSTR next
= strchr( ptr
, ':' );
3145 if (next
) *next
++ = 0;
3146 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3147 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3149 strcpy( unixname
, home
);
3150 strcat( unixname
, ptr
+ 1 );
3151 ReadFontDir( unixname
, TRUE
);
3152 HeapFree( GetProcessHeap(), 0, unixname
);
3155 ReadFontDir( ptr
, TRUE
);
3158 HeapFree( GetProcessHeap(), 0, valueA
);
3160 HeapFree( GetProcessHeap(), 0, valueW
);
3166 /* Mac default font locations. */
3167 ReadFontDir( "/Library/Fonts", TRUE
);
3168 ReadFontDir( "/Network/Library/Fonts", TRUE
);
3169 ReadFontDir( "/System/Library/Fonts", TRUE
);
3170 if ((home
= getenv( "HOME" )))
3172 unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(home
)+15 );
3173 strcpy( unixname
, home
);
3174 strcat( unixname
, "/Library/Fonts" );
3175 ReadFontDir( unixname
, TRUE
);
3176 HeapFree( GetProcessHeap(), 0, unixname
);
3181 static BOOL
move_to_front(const WCHAR
*name
)
3183 Family
*family
, *cursor2
;
3184 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3186 if(!strcmpiW(family
->FamilyName
, name
))
3188 list_remove(&family
->entry
);
3189 list_add_head(&font_list
, &family
->entry
);
3196 static BOOL
set_default(const WCHAR
**name_list
)
3200 if (move_to_front(*name_list
)) return TRUE
;
3207 static void reorder_font_list(void)
3209 set_default( default_serif_list
);
3210 set_default( default_fixed_list
);
3211 set_default( default_sans_list
);
3214 /*************************************************************
3217 * Initialize FreeType library and create a list of available faces
3219 BOOL
WineEngInit(void)
3221 HKEY hkey_font_cache
;
3225 /* update locale dependent font info in registry */
3228 if(!init_freetype()) return FALSE
;
3230 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3232 ERR("Failed to create font mutex\n");
3235 WaitForSingleObject(font_mutex
, INFINITE
);
3237 create_font_cache_key(&hkey_font_cache
, &disposition
);
3239 if(disposition
== REG_CREATED_NEW_KEY
)
3242 load_font_list_from_cache(hkey_font_cache
);
3244 RegCloseKey(hkey_font_cache
);
3246 reorder_font_list();
3253 if(disposition
== REG_CREATED_NEW_KEY
)
3254 update_reg_entries();
3256 init_system_links();
3258 ReleaseMutex(font_mutex
);
3263 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3266 TT_HoriHeader
*pHori
;
3270 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3271 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3273 if(height
== 0) height
= 16;
3275 /* Calc. height of EM square:
3277 * For +ve lfHeight we have
3278 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3279 * Re-arranging gives:
3280 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3282 * For -ve lfHeight we have
3284 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3285 * with il = winAscent + winDescent - units_per_em]
3290 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3291 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3292 pHori
->Ascender
- pHori
->Descender
);
3294 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3295 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3303 static struct font_mapping
*map_font_file( const char *name
)
3305 struct font_mapping
*mapping
;
3309 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3310 if (fstat( fd
, &st
) == -1) goto error
;
3312 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3314 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3316 mapping
->refcount
++;
3321 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3324 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3327 if (mapping
->data
== MAP_FAILED
)
3329 HeapFree( GetProcessHeap(), 0, mapping
);
3332 mapping
->refcount
= 1;
3333 mapping
->dev
= st
.st_dev
;
3334 mapping
->ino
= st
.st_ino
;
3335 mapping
->size
= st
.st_size
;
3336 list_add_tail( &mappings_list
, &mapping
->entry
);
3344 static void unmap_font_file( struct font_mapping
*mapping
)
3346 if (!--mapping
->refcount
)
3348 list_remove( &mapping
->entry
);
3349 munmap( mapping
->data
, mapping
->size
);
3350 HeapFree( GetProcessHeap(), 0, mapping
);
3354 static LONG
load_VDMX(GdiFont
*, LONG
);
3356 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3363 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3367 if (!(font
->mapping
= map_font_file( face
->file
)))
3369 WARN("failed to map %s\n", debugstr_a(face
->file
));
3372 data_ptr
= font
->mapping
->data
;
3373 data_size
= font
->mapping
->size
;
3377 data_ptr
= face
->font_data_ptr
;
3378 data_size
= face
->font_data_size
;
3381 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3383 ERR("FT_New_Face rets %d\n", err
);
3387 /* set it here, as load_VDMX needs it */
3388 font
->ft_face
= ft_face
;
3390 if(FT_IS_SCALABLE(ft_face
)) {
3391 /* load the VDMX table if we have one */
3392 font
->ppem
= load_VDMX(font
, height
);
3394 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3395 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3397 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3398 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3400 font
->ppem
= height
;
3401 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3402 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3408 static int get_nearest_charset(Face
*face
, int *cp
)
3410 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3411 a single face with the requested charset. The idea is to check if
3412 the selected font supports the current ANSI codepage, if it does
3413 return the corresponding charset, else return the first charset */
3416 int acp
= GetACP(), i
;
3420 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3421 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3422 return csi
.ciCharset
;
3424 for(i
= 0; i
< 32; i
++) {
3426 if(face
->fs
.fsCsb
[0] & fs0
) {
3427 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3429 return csi
.ciCharset
;
3432 FIXME("TCI failing on %x\n", fs0
);
3436 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3437 face
->fs
.fsCsb
[0], face
->file
);
3439 return DEFAULT_CHARSET
;
3442 static GdiFont
*alloc_font(void)
3444 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3446 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3447 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3449 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3450 ret
->total_kern_pairs
= (DWORD
)-1;
3451 ret
->kern_pairs
= NULL
;
3452 list_init(&ret
->hfontlist
);
3453 list_init(&ret
->child_fonts
);
3457 static void free_font(GdiFont
*font
)
3459 struct list
*cursor
, *cursor2
;
3462 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3464 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3465 list_remove(cursor
);
3467 free_font(child
->font
);
3468 HeapFree(GetProcessHeap(), 0, child
);
3471 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3473 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3474 DeleteObject(hfontlist
->hfont
);
3475 list_remove(&hfontlist
->entry
);
3476 HeapFree(GetProcessHeap(), 0, hfontlist
);
3479 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3480 if (font
->mapping
) unmap_font_file( font
->mapping
);
3481 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3482 HeapFree(GetProcessHeap(), 0, font
->potm
);
3483 HeapFree(GetProcessHeap(), 0, font
->name
);
3484 for (i
= 0; i
< font
->gmsize
; i
++)
3485 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3486 HeapFree(GetProcessHeap(), 0, font
->gm
);
3487 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3488 HeapFree(GetProcessHeap(), 0, font
);
3492 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3494 FT_Face ft_face
= font
->ft_face
;
3498 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3505 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3507 /* make sure value of len is the value freetype says it needs */
3510 FT_ULong needed
= 0;
3511 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3512 if( !err
&& needed
< len
) len
= needed
;
3514 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3517 TRACE("Can't find table %c%c%c%c\n",
3518 /* bytes were reversed */
3519 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3520 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3526 /*************************************************************
3529 * load the vdmx entry for the specified height
3532 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3533 ( ( (FT_ULong)_x4 << 24 ) | \
3534 ( (FT_ULong)_x3 << 16 ) | \
3535 ( (FT_ULong)_x2 << 8 ) | \
3538 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3553 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3557 BYTE devXRatio
, devYRatio
;
3558 USHORT numRecs
, numRatios
;
3559 DWORD result
, offset
= -1;
3563 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3565 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3568 /* FIXME: need the real device aspect ratio */
3572 numRecs
= GET_BE_WORD(hdr
[1]);
3573 numRatios
= GET_BE_WORD(hdr
[2]);
3575 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3576 for(i
= 0; i
< numRatios
; i
++) {
3579 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3580 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3583 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3585 if((ratio
.xRatio
== 0 &&
3586 ratio
.yStartRatio
== 0 &&
3587 ratio
.yEndRatio
== 0) ||
3588 (devXRatio
== ratio
.xRatio
&&
3589 devYRatio
>= ratio
.yStartRatio
&&
3590 devYRatio
<= ratio
.yEndRatio
))
3592 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3593 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3594 offset
= GET_BE_WORD(tmp
);
3600 FIXME("No suitable ratio found\n");
3604 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3606 BYTE startsz
, endsz
;
3609 recs
= GET_BE_WORD(group
.recs
);
3610 startsz
= group
.startsz
;
3611 endsz
= group
.endsz
;
3613 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3615 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3616 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3617 if(result
== GDI_ERROR
) {
3618 FIXME("Failed to retrieve vTable\n");
3623 for(i
= 0; i
< recs
; i
++) {
3624 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3625 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3626 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3628 if(yMax
+ -yMin
== height
) {
3631 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3634 if(yMax
+ -yMin
> height
) {
3637 goto end
; /* failed */
3639 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3640 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3641 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3642 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3648 TRACE("ppem not found for height %d\n", height
);
3652 HeapFree(GetProcessHeap(), 0, vTable
);
3658 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3660 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3661 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3662 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3663 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3664 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3667 static void calc_hash(FONT_DESC
*pfd
)
3669 DWORD hash
= 0, *ptr
, two_chars
;
3673 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3675 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3677 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3679 pwc
= (WCHAR
*)&two_chars
;
3681 *pwc
= toupperW(*pwc
);
3683 *pwc
= toupperW(*pwc
);
3687 hash
^= !pfd
->can_use_bitmap
;
3692 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3697 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3701 fd
.can_use_bitmap
= can_use_bitmap
;
3704 /* try the child list */
3705 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3706 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3707 if(!fontcmp(ret
, &fd
)) {
3708 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3709 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3710 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3711 if(hflist
->hfont
== hfont
)
3717 /* try the in-use list */
3718 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3719 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3720 if(!fontcmp(ret
, &fd
)) {
3721 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3722 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3723 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3724 if(hflist
->hfont
== hfont
)
3727 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3728 hflist
->hfont
= hfont
;
3729 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3734 /* then the unused list */
3735 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3736 while(font_elem_ptr
) {
3737 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3738 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3739 if(!fontcmp(ret
, &fd
)) {
3740 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3741 assert(list_empty(&ret
->hfontlist
));
3742 TRACE("Found %p in unused list\n", ret
);
3743 list_remove(&ret
->entry
);
3744 list_add_head(&gdi_font_list
, &ret
->entry
);
3745 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3746 hflist
->hfont
= hfont
;
3747 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3754 static void add_to_cache(GdiFont
*font
)
3756 static DWORD cache_num
= 1;
3758 font
->cache_num
= cache_num
++;
3759 list_add_head(&gdi_font_list
, &font
->entry
);
3762 /*************************************************************
3763 * create_child_font_list
3765 static BOOL
create_child_font_list(GdiFont
*font
)
3768 SYSTEM_LINKS
*font_link
;
3769 CHILD_FONT
*font_link_entry
, *new_child
;
3773 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3774 font_name
= psub
? psub
->to
.name
: font
->name
;
3775 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3777 if(!strcmpiW(font_link
->font_name
, font_name
))
3779 TRACE("found entry in system list\n");
3780 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3782 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3783 new_child
->face
= font_link_entry
->face
;
3784 new_child
->font
= NULL
;
3785 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3786 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3793 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3794 * Sans Serif. This is how asian windows get default fallbacks for fonts
3796 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3797 font
->charset
!= OEM_CHARSET
&&
3798 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3799 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3801 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3803 TRACE("found entry in default fallback list\n");
3804 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3806 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3807 new_child
->face
= font_link_entry
->face
;
3808 new_child
->font
= NULL
;
3809 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3810 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3820 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3822 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3824 if (pFT_Set_Charmap
)
3827 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3829 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3831 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3833 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3835 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3836 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3838 switch (ft_face
->charmaps
[i
]->platform_id
)
3841 cmap_def
= ft_face
->charmaps
[i
];
3843 case 0: /* Apple Unicode */
3844 cmap0
= ft_face
->charmaps
[i
];
3846 case 1: /* Macintosh */
3847 cmap1
= ft_face
->charmaps
[i
];
3850 cmap2
= ft_face
->charmaps
[i
];
3852 case 3: /* Microsoft */
3853 cmap3
= ft_face
->charmaps
[i
];
3858 if (cmap3
) /* prefer Microsoft cmap table */
3859 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3861 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3863 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3865 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3867 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3869 return ft_err
== FT_Err_Ok
;
3872 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3876 /*************************************************************
3879 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
3880 LPCWSTR output
, const DEVMODEW
*devmode
)
3882 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
3884 if (!physdev
) return FALSE
;
3885 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
3890 /*************************************************************
3893 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
3895 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3896 HeapFree( GetProcessHeap(), 0, physdev
);
3901 /*************************************************************
3902 * freetype_SelectFont
3904 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
3906 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3908 Face
*face
, *best
, *best_bitmap
;
3909 Family
*family
, *last_resort_family
;
3910 struct list
*family_elem_ptr
, *face_elem_ptr
;
3911 INT height
, width
= 0;
3912 unsigned int score
= 0, new_score
;
3913 signed int diff
= 0, newdiff
;
3914 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
3919 FontSubst
*psub
= NULL
;
3920 DC
*dc
= get_dc_ptr( dev
->hdc
);
3922 if (!hfont
) /* notification that the font has been changed by another driver */
3925 physdev
->font
= NULL
;
3926 release_dc_ptr( dc
);
3930 GetObjectW( hfont
, sizeof(lf
), &lf
);
3931 lf
.lfWidth
= abs(lf
.lfWidth
);
3933 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
3935 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3936 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3937 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3940 if(dc
->GraphicsMode
== GM_ADVANCED
)
3941 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3944 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3945 font scaling abilities. */
3946 dcmat
.eM11
= dcmat
.eM22
= dc
->vport2WorldValid
? fabs(dc
->xformWorld2Vport
.eM22
) : 1.0;
3947 dcmat
.eM21
= dcmat
.eM12
= 0;
3950 /* Try to avoid not necessary glyph transformations */
3951 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3953 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3954 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3955 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3958 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3959 dcmat
.eM21
, dcmat
.eM22
);
3962 EnterCriticalSection( &freetype_cs
);
3964 /* check the cache first */
3965 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3966 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3970 if(list_empty(&font_list
)) /* No fonts installed */
3972 TRACE("No fonts installed\n");
3976 TRACE("not in cache\n");
3979 ret
->font_desc
.matrix
= dcmat
;
3980 ret
->font_desc
.lf
= lf
;
3981 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
3982 calc_hash(&ret
->font_desc
);
3983 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3984 hflist
->hfont
= hfont
;
3985 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3987 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3988 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3989 original value lfCharSet. Note this is a special case for
3990 Symbol and doesn't happen at least for "Wingdings*" */
3992 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
3993 lf
.lfCharSet
= SYMBOL_CHARSET
;
3995 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
3996 switch(lf
.lfCharSet
) {
3997 case DEFAULT_CHARSET
:
3998 csi
.fs
.fsCsb
[0] = 0;
4001 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4002 csi
.fs
.fsCsb
[0] = 0;
4008 if(lf
.lfFaceName
[0] != '\0') {
4009 SYSTEM_LINKS
*font_link
;
4010 CHILD_FONT
*font_link_entry
;
4011 LPWSTR FaceName
= lf
.lfFaceName
;
4013 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4016 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4017 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4018 if (psub
->to
.charset
!= -1)
4019 lf
.lfCharSet
= psub
->to
.charset
;
4022 /* We want a match on name and charset or just name if
4023 charset was DEFAULT_CHARSET. If the latter then
4024 we fixup the returned charset later in get_nearest_charset
4025 where we'll either use the charset of the current ansi codepage
4026 or if that's unavailable the first charset that the font supports.
4028 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4029 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4030 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4031 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4033 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4034 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4035 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
4036 if(face
->scalable
|| can_use_bitmap
)
4042 /* Search by full face name. */
4043 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4044 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4045 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4046 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4047 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4048 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]))
4050 if(face
->scalable
|| can_use_bitmap
)
4057 * Try check the SystemLink list first for a replacement font.
4058 * We may find good replacements there.
4060 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4062 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4063 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4065 TRACE("found entry in system list\n");
4066 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4068 face
= font_link_entry
->face
;
4069 family
= face
->family
;
4070 if(csi
.fs
.fsCsb
[0] &
4071 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
4073 if(face
->scalable
|| can_use_bitmap
)
4081 psub
= NULL
; /* substitution is no more relevant */
4083 /* If requested charset was DEFAULT_CHARSET then try using charset
4084 corresponding to the current ansi codepage */
4085 if (!csi
.fs
.fsCsb
[0])
4088 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4089 FIXME("TCI failed on codepage %d\n", acp
);
4090 csi
.fs
.fsCsb
[0] = 0;
4092 lf
.lfCharSet
= csi
.ciCharset
;
4095 want_vertical
= (lf
.lfFaceName
[0] == '@');
4097 /* Face families are in the top 4 bits of lfPitchAndFamily,
4098 so mask with 0xF0 before testing */
4100 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4101 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4102 strcpyW(lf
.lfFaceName
, defFixed
);
4103 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4104 strcpyW(lf
.lfFaceName
, defSerif
);
4105 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4106 strcpyW(lf
.lfFaceName
, defSans
);
4108 strcpyW(lf
.lfFaceName
, defSans
);
4109 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4110 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4111 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4112 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4113 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4114 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
4115 if(face
->scalable
|| can_use_bitmap
)
4121 last_resort_family
= NULL
;
4122 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4123 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4124 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4125 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4126 if(face
->vertical
== want_vertical
&&
4127 (csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))) {
4130 if(can_use_bitmap
&& !last_resort_family
)
4131 last_resort_family
= family
;
4136 if(last_resort_family
) {
4137 family
= last_resort_family
;
4138 csi
.fs
.fsCsb
[0] = 0;
4142 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4143 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4144 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4145 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4146 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4147 csi
.fs
.fsCsb
[0] = 0;
4148 WARN("just using first face for now\n");
4151 if(can_use_bitmap
&& !last_resort_family
)
4152 last_resort_family
= family
;
4155 if(!last_resort_family
) {
4156 FIXME("can't find a single appropriate font - bailing\n");
4162 WARN("could only find a bitmap font - this will probably look awful!\n");
4163 family
= last_resort_family
;
4164 csi
.fs
.fsCsb
[0] = 0;
4167 it
= lf
.lfItalic
? 1 : 0;
4168 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4170 height
= lf
.lfHeight
;
4172 face
= best
= best_bitmap
= NULL
;
4173 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
4175 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
4179 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4180 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4181 new_score
= (italic
^ it
) + (bold
^ bd
);
4182 if(!best
|| new_score
<= score
)
4184 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4185 italic
, bold
, it
, bd
);
4188 if(best
->scalable
&& score
== 0) break;
4192 newdiff
= height
- (signed int)(best
->size
.height
);
4194 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4195 if(!best_bitmap
|| new_score
< score
||
4196 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4198 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4201 if(score
== 0 && diff
== 0) break;
4208 face
= best
->scalable
? best
: best_bitmap
;
4209 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4210 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4213 height
= lf
.lfHeight
;
4217 if(csi
.fs
.fsCsb
[0]) {
4218 ret
->charset
= lf
.lfCharSet
;
4219 ret
->codepage
= csi
.ciACP
;
4222 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
4224 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4225 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4227 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4229 if(!face
->scalable
) {
4230 /* Windows uses integer scaling factors for bitmap fonts */
4231 INT scale
, scaled_height
;
4232 GdiFont
*cachedfont
;
4234 /* FIXME: rotation of bitmap fonts is ignored */
4235 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4237 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4238 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4239 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4240 /* As we changed the matrix, we need to search the cache for the font again,
4241 * otherwise we might explode the cache. */
4242 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4243 TRACE("Found cached font after non-scalable matrix rescale!\n");
4248 calc_hash(&ret
->font_desc
);
4250 if (height
!= 0) height
= diff
;
4251 height
+= face
->size
.height
;
4253 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4254 scaled_height
= scale
* face
->size
.height
;
4255 /* Only jump to the next height if the difference <= 25% original height */
4256 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4257 /* The jump between unscaled and doubled is delayed by 1 */
4258 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4259 ret
->scale_y
= scale
;
4261 width
= face
->size
.x_ppem
>> 6;
4262 height
= face
->size
.y_ppem
>> 6;
4266 TRACE("font scale y: %f\n", ret
->scale_y
);
4268 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4277 ret
->ntmFlags
= face
->ntmFlags
;
4279 if (ret
->charset
== SYMBOL_CHARSET
&&
4280 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4283 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4287 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4290 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4291 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4292 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4293 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4294 create_child_font_list(ret
);
4296 if (face
->vertical
) /* We need to try to load the GSUB table */
4298 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4299 if (length
!= GDI_ERROR
)
4301 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4302 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4303 TRACE("Loaded GSUB table of %i bytes\n",length
);
4307 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4314 physdev
->font
= ret
;
4316 LeaveCriticalSection( &freetype_cs
);
4317 release_dc_ptr( dc
);
4318 return ret
? hfont
: 0;
4321 static void dump_gdi_font_list(void)
4324 struct list
*elem_ptr
;
4326 TRACE("---------- gdiFont Cache ----------\n");
4327 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4328 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4329 TRACE("gdiFont=%p %s %d\n",
4330 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4333 TRACE("---------- Unused gdiFont Cache ----------\n");
4334 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4335 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4336 TRACE("gdiFont=%p %s %d\n",
4337 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4340 TRACE("---------- Child gdiFont Cache ----------\n");
4341 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4342 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4343 TRACE("gdiFont=%p %s %d\n",
4344 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4348 /*************************************************************
4349 * WineEngDestroyFontInstance
4351 * free the gdiFont associated with this handle
4354 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4359 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4363 EnterCriticalSection( &freetype_cs
);
4365 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4367 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4368 while(hfontlist_elem_ptr
) {
4369 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4370 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4371 if(hflist
->hfont
== handle
) {
4372 TRACE("removing child font %p from child list\n", gdiFont
);
4373 list_remove(&gdiFont
->entry
);
4374 LeaveCriticalSection( &freetype_cs
);
4380 TRACE("destroying hfont=%p\n", handle
);
4382 dump_gdi_font_list();
4384 font_elem_ptr
= list_head(&gdi_font_list
);
4385 while(font_elem_ptr
) {
4386 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4387 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4389 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4390 while(hfontlist_elem_ptr
) {
4391 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4392 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4393 if(hflist
->hfont
== handle
) {
4394 list_remove(&hflist
->entry
);
4395 HeapFree(GetProcessHeap(), 0, hflist
);
4399 if(list_empty(&gdiFont
->hfontlist
)) {
4400 TRACE("Moving to Unused list\n");
4401 list_remove(&gdiFont
->entry
);
4402 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4407 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4408 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4409 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4410 while(font_elem_ptr
) {
4411 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4412 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4413 TRACE("freeing %p\n", gdiFont
);
4414 list_remove(&gdiFont
->entry
);
4417 LeaveCriticalSection( &freetype_cs
);
4421 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4428 id
+= IDS_FIRST_SCRIPT
;
4429 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4430 if (!rsrc
) return 0;
4431 hMem
= LoadResource( gdi32_module
, rsrc
);
4432 if (!hMem
) return 0;
4434 p
= LockResource( hMem
);
4436 while (id
--) p
+= *p
+ 1;
4438 i
= min(LF_FACESIZE
- 1, *p
);
4439 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4445 /***************************************************
4446 * create_enum_charset_list
4448 * This function creates charset enumeration list because in DEFAULT_CHARSET
4449 * case, the ANSI codepage's charset takes precedence over other charsets.
4450 * This function works as a filter other than DEFAULT_CHARSET case.
4452 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4457 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4458 csi
.fs
.fsCsb
[0] != 0) {
4459 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4460 list
->element
[n
].charset
= csi
.ciCharset
;
4461 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4464 else { /* charset is DEFAULT_CHARSET or invalid. */
4467 /* Set the current codepage's charset as the first element. */
4469 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4470 csi
.fs
.fsCsb
[0] != 0) {
4471 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4472 list
->element
[n
].charset
= csi
.ciCharset
;
4473 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4477 /* Fill out left elements. */
4478 for (i
= 0; i
< 32; i
++) {
4480 fs
.fsCsb
[0] = 1L << i
;
4482 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4483 continue; /* skip, already added. */
4484 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4485 continue; /* skip, this is an invalid fsCsb bit. */
4487 list
->element
[n
].mask
= fs
.fsCsb
[0];
4488 list
->element
[n
].charset
= csi
.ciCharset
;
4489 load_script_name( i
, list
->element
[n
].name
);
4498 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4499 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4504 if (face
->cached_enum_data
)
4507 *pelf
= face
->cached_enum_data
->elf
;
4508 *pntm
= face
->cached_enum_data
->ntm
;
4509 *ptype
= face
->cached_enum_data
->type
;
4513 font
= alloc_font();
4515 if(face
->scalable
) {
4516 height
= -2048; /* 2048 is the most common em size */
4519 height
= face
->size
.y_ppem
>> 6;
4520 width
= face
->size
.x_ppem
>> 6;
4522 font
->scale_y
= 1.0;
4524 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4530 font
->name
= strdupW(face
->family
->FamilyName
);
4531 font
->ntmFlags
= face
->ntmFlags
;
4533 if (get_outline_text_metrics(font
))
4535 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4537 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4539 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4540 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4542 lstrcpynW(pelf
->elfFullName
,
4543 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4545 lstrcpynW(pelf
->elfStyle
,
4546 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4551 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4553 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4555 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4557 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4559 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4560 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4563 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4564 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4565 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4566 pntm
->ntmFontSig
= face
->fs
;
4568 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4570 pelf
->elfLogFont
.lfEscapement
= 0;
4571 pelf
->elfLogFont
.lfOrientation
= 0;
4572 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4573 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4574 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4575 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4576 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4577 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4578 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4579 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4580 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4581 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4582 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4585 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4586 *ptype
|= TRUETYPE_FONTTYPE
;
4587 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4588 *ptype
|= DEVICE_FONTTYPE
;
4589 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4590 *ptype
|= RASTER_FONTTYPE
;
4592 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4593 if (face
->cached_enum_data
)
4595 face
->cached_enum_data
->elf
= *pelf
;
4596 face
->cached_enum_data
->ntm
= *pntm
;
4597 face
->cached_enum_data
->type
= *ptype
;
4603 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4605 struct list
*face_elem_ptr
;
4607 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4609 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
)
4611 static const WCHAR spaceW
[] = { ' ',0 };
4612 WCHAR full_family_name
[LF_FULLFACESIZE
];
4613 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4615 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4617 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4618 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4622 strcpyW(full_family_name
, family
->FamilyName
);
4623 strcatW(full_family_name
, spaceW
);
4624 strcatW(full_family_name
, face
->StyleName
);
4625 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4631 static BOOL
face_matches(Face
*face
, const LOGFONTW
*lf
)
4633 static const WCHAR spaceW
[] = { ' ',0 };
4634 WCHAR full_family_name
[LF_FULLFACESIZE
];
4636 if (!strcmpiW(lf
->lfFaceName
, face
->family
->FamilyName
)) return TRUE
;
4638 if (strlenW(face
->family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4640 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4641 debugstr_w(face
->family
->FamilyName
), debugstr_w(face
->StyleName
));
4645 strcpyW(full_family_name
, face
->family
->FamilyName
);
4646 strcatW(full_family_name
, spaceW
);
4647 strcatW(full_family_name
, face
->StyleName
);
4648 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4651 static BOOL
enum_face_charsets(Face
*face
, struct enum_charset_list
*list
,
4652 FONTENUMPROCW proc
, LPARAM lparam
)
4655 NEWTEXTMETRICEXW ntm
;
4659 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4660 for(i
= 0; i
< list
->total
; i
++) {
4661 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4662 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4663 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4664 i
= list
->total
; /* break out of loop after enumeration */
4665 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4668 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4669 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4670 if (!elf
.elfScript
[0])
4671 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4673 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4674 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4675 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4676 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4677 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4678 ntm
.ntmTm
.ntmFlags
);
4679 /* release section before callback (FIXME) */
4680 LeaveCriticalSection( &freetype_cs
);
4681 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4682 EnterCriticalSection( &freetype_cs
);
4687 /*************************************************************
4688 * freetype_EnumFonts
4690 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4694 struct list
*family_elem_ptr
, *face_elem_ptr
;
4696 struct enum_charset_list enum_charsets
;
4700 lf
.lfCharSet
= DEFAULT_CHARSET
;
4701 lf
.lfPitchAndFamily
= 0;
4702 lf
.lfFaceName
[0] = 0;
4706 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4708 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4711 EnterCriticalSection( &freetype_cs
);
4712 if(plf
->lfFaceName
[0]) {
4714 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4717 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4718 debugstr_w(psub
->to
.name
));
4720 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4724 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4725 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4726 if(family_matches(family
, plf
)) {
4727 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4728 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4729 if (!face_matches(face
, plf
)) continue;
4730 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4735 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4736 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4737 face_elem_ptr
= list_head(&family
->faces
);
4738 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4739 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4742 LeaveCriticalSection( &freetype_cs
);
4746 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4748 pt
->x
.value
= vec
->x
>> 6;
4749 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4750 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4751 pt
->y
.value
= vec
->y
>> 6;
4752 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4753 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4757 /***************************************************
4758 * According to the MSDN documentation on WideCharToMultiByte,
4759 * certain codepages cannot set the default_used parameter.
4760 * This returns TRUE if the codepage can set that parameter, false else
4761 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4763 static BOOL
codepage_sets_default_used(UINT codepage
)
4777 * GSUB Table handling functions
4780 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4782 const GSUB_CoverageFormat1
* cf1
;
4786 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4788 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4790 TRACE("Coverage Format 1, %i glyphs\n",count
);
4791 for (i
= 0; i
< count
; i
++)
4792 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4796 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4798 const GSUB_CoverageFormat2
* cf2
;
4801 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4803 count
= GET_BE_WORD(cf2
->RangeCount
);
4804 TRACE("Coverage Format 2, %i ranges\n",count
);
4805 for (i
= 0; i
< count
; i
++)
4807 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4809 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4810 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4812 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4813 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4819 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4824 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4826 const GSUB_ScriptList
*script
;
4827 const GSUB_Script
*deflt
= NULL
;
4829 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4831 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4832 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4834 const GSUB_Script
*scr
;
4837 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4838 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4840 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4842 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4848 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4852 const GSUB_LangSys
*Lang
;
4854 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4856 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4858 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4859 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4861 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4864 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4867 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4873 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4876 const GSUB_FeatureList
*feature
;
4877 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4879 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4880 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4882 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4883 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4885 const GSUB_Feature
*feat
;
4886 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4893 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4897 const GSUB_LookupList
*lookup
;
4898 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4900 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4901 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4903 const GSUB_LookupTable
*look
;
4904 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4905 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4906 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4907 if (GET_BE_WORD(look
->LookupType
) != 1)
4908 FIXME("We only handle SubType 1\n");
4913 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4915 const GSUB_SingleSubstFormat1
*ssf1
;
4916 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4917 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4918 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4920 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4921 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4922 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4924 TRACE(" Glyph 0x%x ->",glyph
);
4925 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4926 TRACE(" 0x%x\n",glyph
);
4931 const GSUB_SingleSubstFormat2
*ssf2
;
4935 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4936 offset
= GET_BE_WORD(ssf1
->Coverage
);
4937 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4938 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4939 TRACE(" Coverage index %i\n",index
);
4942 TRACE(" Glyph is 0x%x ->",glyph
);
4943 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4944 TRACE("0x%x\n",glyph
);
4953 static const char* get_opentype_script(const GdiFont
*font
)
4956 * I am not sure if this is the correct way to generate our script tag
4959 switch (font
->charset
)
4961 case ANSI_CHARSET
: return "latn";
4962 case BALTIC_CHARSET
: return "latn"; /* ?? */
4963 case CHINESEBIG5_CHARSET
: return "hani";
4964 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4965 case GB2312_CHARSET
: return "hani";
4966 case GREEK_CHARSET
: return "grek";
4967 case HANGUL_CHARSET
: return "hang";
4968 case RUSSIAN_CHARSET
: return "cyrl";
4969 case SHIFTJIS_CHARSET
: return "kana";
4970 case TURKISH_CHARSET
: return "latn"; /* ?? */
4971 case VIETNAMESE_CHARSET
: return "latn";
4972 case JOHAB_CHARSET
: return "latn"; /* ?? */
4973 case ARABIC_CHARSET
: return "arab";
4974 case HEBREW_CHARSET
: return "hebr";
4975 case THAI_CHARSET
: return "thai";
4976 default: return "latn";
4980 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
4982 const GSUB_Header
*header
;
4983 const GSUB_Script
*script
;
4984 const GSUB_LangSys
*language
;
4985 const GSUB_Feature
*feature
;
4987 if (!font
->GSUB_Table
)
4990 header
= font
->GSUB_Table
;
4992 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
4995 TRACE("Script not found\n");
4998 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5001 TRACE("Language not found\n");
5004 feature
= GSUB_get_feature(header
, language
, "vrt2");
5006 feature
= GSUB_get_feature(header
, language
, "vert");
5009 TRACE("vrt2/vert feature not found\n");
5012 return GSUB_apply_feature(header
, feature
, glyph
);
5015 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5019 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5020 WCHAR wc
= (WCHAR
)glyph
;
5022 BOOL
*default_used_pointer
;
5025 default_used_pointer
= NULL
;
5026 default_used
= FALSE
;
5027 if (codepage_sets_default_used(font
->codepage
))
5028 default_used_pointer
= &default_used
;
5029 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5032 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5033 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5037 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5039 if (glyph
< 0x100) glyph
+= 0xf000;
5040 /* there is a number of old pre-Unicode "broken" TTFs, which
5041 do have symbols at U+00XX instead of U+f0XX */
5042 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5043 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5045 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5050 /*************************************************************
5051 * freetype_GetGlyphIndices
5053 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5055 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5058 BOOL got_default
= FALSE
;
5062 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5063 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5066 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5068 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5073 EnterCriticalSection( &freetype_cs
);
5075 for(i
= 0; i
< count
; i
++)
5077 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5082 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5084 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5085 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5090 get_text_metrics(physdev
->font
, &textm
);
5091 default_char
= textm
.tmDefaultChar
;
5095 pgi
[i
] = default_char
;
5098 LeaveCriticalSection( &freetype_cs
);
5102 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5104 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5105 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5108 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5110 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5111 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5114 static inline BYTE
get_max_level( UINT format
)
5118 case GGO_GRAY2_BITMAP
: return 4;
5119 case GGO_GRAY4_BITMAP
: return 16;
5120 case GGO_GRAY8_BITMAP
: return 64;
5125 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5127 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5128 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5131 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5132 FT_Face ft_face
= incoming_font
->ft_face
;
5133 GdiFont
*font
= incoming_font
;
5134 FT_UInt glyph_index
;
5135 DWORD width
, height
, pitch
, needed
= 0;
5136 FT_Bitmap ft_bitmap
;
5138 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5140 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5141 double widthRatio
= 1.0;
5142 FT_Matrix transMat
= identityMat
;
5143 FT_Matrix transMatUnrotated
;
5144 BOOL needsTransform
= FALSE
;
5145 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5146 UINT original_index
;
5148 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5149 buflen
, buf
, lpmat
);
5151 TRACE("font transform %f %f %f %f\n",
5152 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5153 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5155 if(format
& GGO_GLYPH_INDEX
) {
5156 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5157 original_index
= glyph
;
5158 format
&= ~GGO_GLYPH_INDEX
;
5160 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5161 ft_face
= font
->ft_face
;
5162 original_index
= glyph_index
;
5165 if(format
& GGO_UNHINTED
) {
5166 load_flags
|= FT_LOAD_NO_HINTING
;
5167 format
&= ~GGO_UNHINTED
;
5170 /* tategaki never appears to happen to lower glyph index */
5171 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5174 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5175 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5176 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5177 font
->gmsize
* sizeof(GM
*));
5179 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5180 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5182 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5183 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5184 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5185 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5186 return 1; /* FIXME */
5190 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5191 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5193 /* Scaling factor */
5198 get_text_metrics(font
, &tm
);
5200 widthRatio
= (double)font
->aveWidth
;
5201 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5204 widthRatio
= font
->scale_y
;
5206 /* Scaling transform */
5207 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5210 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5213 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5215 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5216 needsTransform
= TRUE
;
5219 /* Slant transform */
5220 if (font
->fake_italic
) {
5223 slantMat
.xx
= (1 << 16);
5224 slantMat
.xy
= ((1 << 16) >> 2);
5226 slantMat
.yy
= (1 << 16);
5227 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5228 needsTransform
= TRUE
;
5231 /* Rotation transform */
5232 transMatUnrotated
= transMat
;
5233 if(font
->orientation
&& !tategaki
) {
5234 FT_Matrix rotationMat
;
5236 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5237 pFT_Vector_Unit(&vecAngle
, angle
);
5238 rotationMat
.xx
= vecAngle
.x
;
5239 rotationMat
.xy
= -vecAngle
.y
;
5240 rotationMat
.yx
= -rotationMat
.xy
;
5241 rotationMat
.yy
= rotationMat
.xx
;
5243 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5244 needsTransform
= TRUE
;
5247 /* World transform */
5248 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5251 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5252 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5253 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5254 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5255 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5256 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5257 needsTransform
= TRUE
;
5260 /* Extra transformation specified by caller */
5261 if (!is_identity_MAT2(lpmat
))
5264 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5265 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5266 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5267 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5268 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5269 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5270 needsTransform
= TRUE
;
5273 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5274 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5275 format
== GGO_GRAY8_BITMAP
))
5277 load_flags
|= FT_LOAD_NO_BITMAP
;
5280 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5283 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5287 if(!needsTransform
) {
5288 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5289 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5290 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5292 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5293 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5294 ft_face
->glyph
->metrics
.height
) & -64;
5295 lpgm
->gmCellIncX
= adv
;
5296 lpgm
->gmCellIncY
= 0;
5303 for(xc
= 0; xc
< 2; xc
++) {
5304 for(yc
= 0; yc
< 2; yc
++) {
5305 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5306 xc
* ft_face
->glyph
->metrics
.width
);
5307 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5308 yc
* ft_face
->glyph
->metrics
.height
;
5309 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5310 pFT_Vector_Transform(&vec
, &transMat
);
5311 if(xc
== 0 && yc
== 0) {
5312 left
= right
= vec
.x
;
5313 top
= bottom
= vec
.y
;
5315 if(vec
.x
< left
) left
= vec
.x
;
5316 else if(vec
.x
> right
) right
= vec
.x
;
5317 if(vec
.y
< bottom
) bottom
= vec
.y
;
5318 else if(vec
.y
> top
) top
= vec
.y
;
5323 right
= (right
+ 63) & -64;
5324 bottom
= bottom
& -64;
5325 top
= (top
+ 63) & -64;
5327 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5328 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5330 pFT_Vector_Transform(&vec
, &transMat
);
5331 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5332 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5334 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5336 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5337 adv
= (vec
.x
+63) >> 6;
5341 bbx
= (right
- left
) >> 6;
5342 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5343 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5344 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5345 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5347 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5348 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5349 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5351 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5352 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5354 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5355 FONT_GM(font
,original_index
)->adv
= adv
;
5356 FONT_GM(font
,original_index
)->lsb
= lsb
;
5357 FONT_GM(font
,original_index
)->bbx
= bbx
;
5358 FONT_GM(font
,original_index
)->init
= TRUE
;
5361 if(format
== GGO_METRICS
)
5363 return 1; /* FIXME */
5366 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5367 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5369 TRACE("loaded a bitmap\n");
5375 width
= lpgm
->gmBlackBoxX
;
5376 height
= lpgm
->gmBlackBoxY
;
5377 pitch
= ((width
+ 31) >> 5) << 2;
5378 needed
= pitch
* height
;
5380 if(!buf
|| !buflen
) break;
5382 switch(ft_face
->glyph
->format
) {
5383 case ft_glyph_format_bitmap
:
5385 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5386 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5387 INT h
= ft_face
->glyph
->bitmap
.rows
;
5389 memcpy(dst
, src
, w
);
5390 src
+= ft_face
->glyph
->bitmap
.pitch
;
5396 case ft_glyph_format_outline
:
5397 ft_bitmap
.width
= width
;
5398 ft_bitmap
.rows
= height
;
5399 ft_bitmap
.pitch
= pitch
;
5400 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5401 ft_bitmap
.buffer
= buf
;
5404 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5406 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5408 /* Note: FreeType will only set 'black' bits for us. */
5409 memset(buf
, 0, needed
);
5410 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5414 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5419 case GGO_GRAY2_BITMAP
:
5420 case GGO_GRAY4_BITMAP
:
5421 case GGO_GRAY8_BITMAP
:
5422 case WINE_GGO_GRAY16_BITMAP
:
5424 unsigned int max_level
, row
, col
;
5427 width
= lpgm
->gmBlackBoxX
;
5428 height
= lpgm
->gmBlackBoxY
;
5429 pitch
= (width
+ 3) / 4 * 4;
5430 needed
= pitch
* height
;
5432 if(!buf
|| !buflen
) break;
5434 max_level
= get_max_level( format
);
5436 switch(ft_face
->glyph
->format
) {
5437 case ft_glyph_format_bitmap
:
5439 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5440 INT h
= ft_face
->glyph
->bitmap
.rows
;
5442 memset( buf
, 0, needed
);
5444 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5445 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5446 src
+= ft_face
->glyph
->bitmap
.pitch
;
5451 case ft_glyph_format_outline
:
5453 ft_bitmap
.width
= width
;
5454 ft_bitmap
.rows
= height
;
5455 ft_bitmap
.pitch
= pitch
;
5456 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5457 ft_bitmap
.buffer
= buf
;
5460 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5462 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5464 memset(ft_bitmap
.buffer
, 0, buflen
);
5466 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5468 if (max_level
!= 255)
5470 for (row
= 0, start
= buf
; row
< height
; row
++)
5472 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5473 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5481 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5487 case WINE_GGO_HRGB_BITMAP
:
5488 case WINE_GGO_HBGR_BITMAP
:
5489 case WINE_GGO_VRGB_BITMAP
:
5490 case WINE_GGO_VBGR_BITMAP
:
5491 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5493 switch (ft_face
->glyph
->format
)
5495 case FT_GLYPH_FORMAT_BITMAP
:
5500 width
= lpgm
->gmBlackBoxX
;
5501 height
= lpgm
->gmBlackBoxY
;
5503 needed
= pitch
* height
;
5505 if (!buf
|| !buflen
) break;
5507 memset(buf
, 0, buflen
);
5509 src
= ft_face
->glyph
->bitmap
.buffer
;
5510 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5512 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5515 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5517 if ( src
[x
/ 8] & masks
[x
% 8] )
5518 ((unsigned int *)dst
)[x
] = ~0u;
5527 case FT_GLYPH_FORMAT_OUTLINE
:
5531 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5532 INT x_shift
, y_shift
;
5534 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5535 FT_Render_Mode render_mode
=
5536 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5537 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5539 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5541 if ( render_mode
== FT_RENDER_MODE_LCD
)
5543 lpgm
->gmBlackBoxX
+= 2;
5544 lpgm
->gmptGlyphOrigin
.x
-= 1;
5548 lpgm
->gmBlackBoxY
+= 2;
5549 lpgm
->gmptGlyphOrigin
.y
+= 1;
5553 width
= lpgm
->gmBlackBoxX
;
5554 height
= lpgm
->gmBlackBoxY
;
5556 needed
= pitch
* height
;
5558 if (!buf
|| !buflen
) break;
5560 memset(buf
, 0, buflen
);
5562 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5564 if ( needsTransform
)
5565 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5567 if ( pFT_Library_SetLcdFilter
)
5568 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5569 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5571 src
= ft_face
->glyph
->bitmap
.buffer
;
5572 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5573 src_width
= ft_face
->glyph
->bitmap
.width
;
5574 src_height
= ft_face
->glyph
->bitmap
.rows
;
5576 if ( render_mode
== FT_RENDER_MODE_LCD
)
5584 rgb_interval
= src_pitch
;
5589 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5590 if ( x_shift
< 0 ) x_shift
= 0;
5591 if ( x_shift
+ (src_width
/ hmul
) > width
)
5592 x_shift
= width
- (src_width
/ hmul
);
5594 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5595 if ( y_shift
< 0 ) y_shift
= 0;
5596 if ( y_shift
+ (src_height
/ vmul
) > height
)
5597 y_shift
= height
- (src_height
/ vmul
);
5599 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5600 while ( src_height
)
5602 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5606 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5607 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5608 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5609 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5613 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5614 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5615 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5616 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5619 src
+= src_pitch
* vmul
;
5628 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5640 int contour
, point
= 0, first_pt
;
5641 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5642 TTPOLYGONHEADER
*pph
;
5644 DWORD pph_start
, cpfx
, type
;
5646 if(buflen
== 0) buf
= NULL
;
5648 if (needsTransform
&& buf
) {
5649 pFT_Outline_Transform(outline
, &transMat
);
5652 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5654 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5657 pph
->dwType
= TT_POLYGON_TYPE
;
5658 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5660 needed
+= sizeof(*pph
);
5662 while(point
<= outline
->contours
[contour
]) {
5663 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5664 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5665 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5669 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5672 } while(point
<= outline
->contours
[contour
] &&
5673 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5674 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5675 /* At the end of a contour Windows adds the start point, but
5677 if(point
> outline
->contours
[contour
] &&
5678 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5680 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5682 } else if(point
<= outline
->contours
[contour
] &&
5683 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5684 /* add closing pt for bezier */
5686 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5694 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5697 pph
->cb
= needed
- pph_start
;
5703 /* Convert the quadratic Beziers to cubic Beziers.
5704 The parametric eqn for a cubic Bezier is, from PLRM:
5705 r(t) = at^3 + bt^2 + ct + r0
5706 with the control points:
5711 A quadratic Bezier has the form:
5712 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5714 So equating powers of t leads to:
5715 r1 = 2/3 p1 + 1/3 p0
5716 r2 = 2/3 p1 + 1/3 p2
5717 and of course r0 = p0, r3 = p2
5720 int contour
, point
= 0, first_pt
;
5721 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5722 TTPOLYGONHEADER
*pph
;
5724 DWORD pph_start
, cpfx
, type
;
5725 FT_Vector cubic_control
[4];
5726 if(buflen
== 0) buf
= NULL
;
5728 if (needsTransform
&& buf
) {
5729 pFT_Outline_Transform(outline
, &transMat
);
5732 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5734 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5737 pph
->dwType
= TT_POLYGON_TYPE
;
5738 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5740 needed
+= sizeof(*pph
);
5742 while(point
<= outline
->contours
[contour
]) {
5743 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5744 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5745 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5748 if(type
== TT_PRIM_LINE
) {
5750 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5754 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5757 /* FIXME: Possible optimization in endpoint calculation
5758 if there are two consecutive curves */
5759 cubic_control
[0] = outline
->points
[point
-1];
5760 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5761 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5762 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5763 cubic_control
[0].x
>>= 1;
5764 cubic_control
[0].y
>>= 1;
5766 if(point
+1 > outline
->contours
[contour
])
5767 cubic_control
[3] = outline
->points
[first_pt
];
5769 cubic_control
[3] = outline
->points
[point
+1];
5770 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5771 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5772 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5773 cubic_control
[3].x
>>= 1;
5774 cubic_control
[3].y
>>= 1;
5777 /* r1 = 1/3 p0 + 2/3 p1
5778 r2 = 1/3 p2 + 2/3 p1 */
5779 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5780 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5781 cubic_control
[2] = cubic_control
[1];
5782 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5783 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5784 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5785 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5787 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5788 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5789 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5794 } while(point
<= outline
->contours
[contour
] &&
5795 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5796 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5797 /* At the end of a contour Windows adds the start point,
5798 but only for Beziers and we've already done that.
5800 if(point
<= outline
->contours
[contour
] &&
5801 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5802 /* This is the closing pt of a bezier, but we've already
5803 added it, so just inc point and carry on */
5810 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5813 pph
->cb
= needed
- pph_start
;
5819 FIXME("Unsupported format %d\n", format
);
5825 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5827 FT_Face ft_face
= font
->ft_face
;
5828 FT_WinFNT_HeaderRec winfnt_header
;
5829 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5830 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5831 font
->potm
->otmSize
= size
;
5833 #define TM font->potm->otmTextMetrics
5834 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5836 TM
.tmHeight
= winfnt_header
.pixel_height
;
5837 TM
.tmAscent
= winfnt_header
.ascent
;
5838 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5839 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5840 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5841 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5842 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5843 TM
.tmWeight
= winfnt_header
.weight
;
5845 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5846 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5847 TM
.tmFirstChar
= winfnt_header
.first_char
;
5848 TM
.tmLastChar
= winfnt_header
.last_char
;
5849 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5850 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5851 TM
.tmItalic
= winfnt_header
.italic
;
5852 TM
.tmUnderlined
= font
->underline
;
5853 TM
.tmStruckOut
= font
->strikeout
;
5854 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5855 TM
.tmCharSet
= winfnt_header
.charset
;
5859 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5860 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5861 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5862 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5863 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5864 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5865 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5866 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5868 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5869 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5871 TM
.tmLastChar
= 255;
5872 TM
.tmDefaultChar
= 32;
5873 TM
.tmBreakChar
= 32;
5874 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5875 TM
.tmUnderlined
= font
->underline
;
5876 TM
.tmStruckOut
= font
->strikeout
;
5877 /* NB inverted meaning of TMPF_FIXED_PITCH */
5878 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5879 TM
.tmCharSet
= font
->charset
;
5887 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5889 double scale_x
, scale_y
;
5893 scale_x
= (double)font
->aveWidth
;
5894 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5897 scale_x
= font
->scale_y
;
5899 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5900 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5902 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5903 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5905 SCALE_Y(ptm
->tmHeight
);
5906 SCALE_Y(ptm
->tmAscent
);
5907 SCALE_Y(ptm
->tmDescent
);
5908 SCALE_Y(ptm
->tmInternalLeading
);
5909 SCALE_Y(ptm
->tmExternalLeading
);
5910 SCALE_Y(ptm
->tmOverhang
);
5912 SCALE_X(ptm
->tmAveCharWidth
);
5913 SCALE_X(ptm
->tmMaxCharWidth
);
5919 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5921 double scale_x
, scale_y
;
5925 scale_x
= (double)font
->aveWidth
;
5926 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5929 scale_x
= font
->scale_y
;
5931 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5932 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5934 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5936 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5937 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5939 SCALE_Y(potm
->otmAscent
);
5940 SCALE_Y(potm
->otmDescent
);
5941 SCALE_Y(potm
->otmLineGap
);
5942 SCALE_Y(potm
->otmsCapEmHeight
);
5943 SCALE_Y(potm
->otmsXHeight
);
5944 SCALE_Y(potm
->otmrcFontBox
.top
);
5945 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5946 SCALE_X(potm
->otmrcFontBox
.left
);
5947 SCALE_X(potm
->otmrcFontBox
.right
);
5948 SCALE_Y(potm
->otmMacAscent
);
5949 SCALE_Y(potm
->otmMacDescent
);
5950 SCALE_Y(potm
->otmMacLineGap
);
5951 SCALE_X(potm
->otmptSubscriptSize
.x
);
5952 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5953 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5954 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5955 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5956 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5957 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5958 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5959 SCALE_Y(potm
->otmsStrikeoutSize
);
5960 SCALE_Y(potm
->otmsStrikeoutPosition
);
5961 SCALE_Y(potm
->otmsUnderscoreSize
);
5962 SCALE_Y(potm
->otmsUnderscorePosition
);
5968 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5972 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
5974 /* Make sure that the font has sane width/height ratio */
5977 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
5979 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
5984 *ptm
= font
->potm
->otmTextMetrics
;
5985 scale_font_metrics(font
, ptm
);
5989 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
5993 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
5995 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6001 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6004 FT_Face ft_face
= font
->ft_face
;
6005 UINT needed
, lenfam
, lensty
;
6007 TT_HoriHeader
*pHori
;
6008 TT_Postscript
*pPost
;
6009 FT_Fixed x_scale
, y_scale
;
6010 WCHAR
*family_nameW
, *style_nameW
;
6011 static const WCHAR spaceW
[] = {' ', '\0'};
6013 INT ascent
, descent
;
6015 TRACE("font=%p\n", font
);
6017 if(!FT_IS_SCALABLE(ft_face
))
6020 needed
= sizeof(*font
->potm
);
6022 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6023 family_nameW
= strdupW(font
->name
);
6025 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6027 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6028 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6029 style_nameW
, lensty
/sizeof(WCHAR
));
6031 /* These names should be read from the TT name table */
6033 /* length of otmpFamilyName */
6036 /* length of otmpFaceName */
6037 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6038 needed
+= lenfam
; /* just the family name */
6040 needed
+= lenfam
+ lensty
; /* family + " " + style */
6043 /* length of otmpStyleName */
6046 /* length of otmpFullName */
6047 needed
+= lenfam
+ lensty
;
6050 x_scale
= ft_face
->size
->metrics
.x_scale
;
6051 y_scale
= ft_face
->size
->metrics
.y_scale
;
6053 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6055 FIXME("Can't find OS/2 table - not TT font?\n");
6059 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6061 FIXME("Can't find HHEA table - not TT font?\n");
6065 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6067 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",
6068 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6069 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6070 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6071 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6072 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6074 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6075 font
->potm
->otmSize
= needed
;
6077 #define TM font->potm->otmTextMetrics
6079 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6080 ascent
= pHori
->Ascender
;
6081 descent
= -pHori
->Descender
;
6083 ascent
= pOS2
->usWinAscent
;
6084 descent
= pOS2
->usWinDescent
;
6088 TM
.tmAscent
= font
->yMax
;
6089 TM
.tmDescent
= -font
->yMin
;
6090 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6092 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6093 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6094 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6095 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6098 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6101 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6103 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6104 ((ascent
+ descent
) -
6105 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6107 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6108 if (TM
.tmAveCharWidth
== 0) {
6109 TM
.tmAveCharWidth
= 1;
6111 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6112 TM
.tmWeight
= FW_REGULAR
;
6113 if (font
->fake_bold
)
6114 TM
.tmWeight
= FW_BOLD
;
6117 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6119 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6120 TM
.tmWeight
= pOS2
->usWeightClass
;
6122 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6123 TM
.tmWeight
= pOS2
->usWeightClass
;
6126 TM
.tmDigitizedAspectX
= 300;
6127 TM
.tmDigitizedAspectY
= 300;
6128 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6129 * symbol range to 0 - f0ff
6132 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6137 case 1257: /* Baltic */
6138 TM
.tmLastChar
= 0xf8fd;
6141 TM
.tmLastChar
= 0xf0ff;
6143 TM
.tmBreakChar
= 0x20;
6144 TM
.tmDefaultChar
= 0x1f;
6148 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6149 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6151 if(pOS2
->usFirstCharIndex
<= 1)
6152 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6153 else if (pOS2
->usFirstCharIndex
> 0xff)
6154 TM
.tmBreakChar
= 0x20;
6156 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6157 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6159 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6160 TM
.tmUnderlined
= font
->underline
;
6161 TM
.tmStruckOut
= font
->strikeout
;
6163 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6164 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6165 (pOS2
->version
== 0xFFFFU
||
6166 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6167 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6169 TM
.tmPitchAndFamily
= 0;
6171 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6173 case PAN_FAMILY_SCRIPT
:
6174 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6177 case PAN_FAMILY_DECORATIVE
:
6178 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6183 case PAN_FAMILY_TEXT_DISPLAY
:
6184 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6185 /* which is clearly not what the panose spec says. */
6187 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6188 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6189 TM
.tmPitchAndFamily
= FF_MODERN
;
6192 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6197 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6200 case PAN_SERIF_COVE
:
6201 case PAN_SERIF_OBTUSE_COVE
:
6202 case PAN_SERIF_SQUARE_COVE
:
6203 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6204 case PAN_SERIF_SQUARE
:
6205 case PAN_SERIF_THIN
:
6206 case PAN_SERIF_BONE
:
6207 case PAN_SERIF_EXAGGERATED
:
6208 case PAN_SERIF_TRIANGLE
:
6209 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6212 case PAN_SERIF_NORMAL_SANS
:
6213 case PAN_SERIF_OBTUSE_SANS
:
6214 case PAN_SERIF_PERP_SANS
:
6215 case PAN_SERIF_FLARED
:
6216 case PAN_SERIF_ROUNDED
:
6217 TM
.tmPitchAndFamily
|= FF_SWISS
;
6224 if(FT_IS_SCALABLE(ft_face
))
6225 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6227 if(FT_IS_SFNT(ft_face
))
6229 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6230 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6232 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6235 TM
.tmCharSet
= font
->charset
;
6237 font
->potm
->otmFiller
= 0;
6238 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6239 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6240 font
->potm
->otmfsType
= pOS2
->fsType
;
6241 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6242 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6243 font
->potm
->otmItalicAngle
= 0; /* POST table */
6244 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6245 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6246 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6247 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6248 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6249 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6250 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6251 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6252 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6253 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6254 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6255 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6256 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6257 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6258 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6259 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6260 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6261 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6262 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6263 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6264 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6265 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6266 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6267 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6269 font
->potm
->otmsUnderscoreSize
= 0;
6270 font
->potm
->otmsUnderscorePosition
= 0;
6272 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6273 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6277 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6278 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6279 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6280 strcpyW((WCHAR
*)cp
, family_nameW
);
6282 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6283 strcpyW((WCHAR
*)cp
, style_nameW
);
6285 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6286 strcpyW((WCHAR
*)cp
, family_nameW
);
6287 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6288 strcatW((WCHAR
*)cp
, spaceW
);
6289 strcatW((WCHAR
*)cp
, style_nameW
);
6290 cp
+= lenfam
+ lensty
;
6293 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6294 strcpyW((WCHAR
*)cp
, family_nameW
);
6295 strcatW((WCHAR
*)cp
, spaceW
);
6296 strcatW((WCHAR
*)cp
, style_nameW
);
6300 HeapFree(GetProcessHeap(), 0, style_nameW
);
6301 HeapFree(GetProcessHeap(), 0, family_nameW
);
6305 /*************************************************************
6306 * freetype_GetGlyphOutline
6308 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6309 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6311 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6316 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6317 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6321 EnterCriticalSection( &freetype_cs
);
6322 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6323 LeaveCriticalSection( &freetype_cs
);
6327 /*************************************************************
6328 * freetype_GetTextMetrics
6330 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6332 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6337 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6338 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6342 EnterCriticalSection( &freetype_cs
);
6343 ret
= get_text_metrics( physdev
->font
, metrics
);
6344 LeaveCriticalSection( &freetype_cs
);
6348 /*************************************************************
6349 * freetype_GetOutlineTextMetrics
6351 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6353 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6358 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6359 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6362 TRACE("font=%p\n", physdev
->font
);
6364 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6367 EnterCriticalSection( &freetype_cs
);
6369 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6371 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6373 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6374 scale_outline_font_metrics(physdev
->font
, potm
);
6376 ret
= physdev
->font
->potm
->otmSize
;
6378 LeaveCriticalSection( &freetype_cs
);
6382 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6384 HFONTLIST
*hfontlist
;
6385 child
->font
= alloc_font();
6386 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6387 if(!child
->font
->ft_face
)
6389 free_font(child
->font
);
6394 child
->font
->font_desc
= font
->font_desc
;
6395 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6396 child
->font
->orientation
= font
->orientation
;
6397 child
->font
->scale_y
= font
->scale_y
;
6398 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6399 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6400 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6401 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6402 child
->font
->base_font
= font
;
6403 list_add_head(&child_font_list
, &child
->font
->entry
);
6404 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6408 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6411 CHILD_FONT
*child_font
;
6414 font
= font
->base_font
;
6416 *linked_font
= font
;
6418 if((*glyph
= get_glyph_index(font
, c
)))
6420 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6424 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6426 if(!child_font
->font
)
6427 if(!load_child_font(font
, child_font
))
6430 if(!child_font
->font
->ft_face
)
6432 g
= get_glyph_index(child_font
->font
, c
);
6433 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6437 *linked_font
= child_font
->font
;
6444 /*************************************************************
6445 * freetype_GetCharWidth
6447 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6449 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6452 FT_UInt glyph_index
;
6453 GdiFont
*linked_font
;
6454 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6458 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6459 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6462 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6465 EnterCriticalSection( &freetype_cs
);
6466 for(c
= firstChar
; c
<= lastChar
; c
++) {
6467 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6468 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6469 &gm
, 0, NULL
, &identity
);
6470 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6472 LeaveCriticalSection( &freetype_cs
);
6476 /*************************************************************
6477 * freetype_GetCharABCWidths
6479 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6481 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6484 FT_UInt glyph_index
;
6485 GdiFont
*linked_font
;
6486 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6490 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6491 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6494 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6497 EnterCriticalSection( &freetype_cs
);
6499 for(c
= firstChar
; c
<= lastChar
; c
++) {
6500 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6501 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6502 &gm
, 0, NULL
, &identity
);
6503 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6504 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6505 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6506 FONT_GM(linked_font
,glyph_index
)->bbx
;
6508 LeaveCriticalSection( &freetype_cs
);
6512 /*************************************************************
6513 * freetype_GetCharABCWidthsI
6515 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6517 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6520 FT_UInt glyph_index
;
6521 GdiFont
*linked_font
;
6522 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6526 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6527 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6530 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6534 EnterCriticalSection( &freetype_cs
);
6536 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6538 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6539 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6540 &gm
, 0, NULL
, &identity
);
6541 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6542 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6543 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6544 - FONT_GM(linked_font
,c
)->bbx
;
6547 for(c
= 0; c
< count
; c
++) {
6548 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6549 &gm
, 0, NULL
, &identity
);
6550 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6551 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6552 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6553 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6556 LeaveCriticalSection( &freetype_cs
);
6560 /*************************************************************
6561 * freetype_GetTextExtentExPoint
6563 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6564 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6566 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6571 FT_UInt glyph_index
;
6572 GdiFont
*linked_font
;
6573 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6577 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6578 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6581 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6584 EnterCriticalSection( &freetype_cs
);
6587 get_text_metrics( physdev
->font
, &tm
);
6588 size
->cy
= tm
.tmHeight
;
6590 for(idx
= 0; idx
< count
; idx
++) {
6591 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6592 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6593 &gm
, 0, NULL
, &identity
);
6594 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6596 if (! pnfit
|| ext
<= max_ext
) {
6606 LeaveCriticalSection( &freetype_cs
);
6607 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6611 /*************************************************************
6612 * freetype_GetTextExtentExPointI
6614 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6615 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6617 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6622 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6626 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6627 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6630 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6633 EnterCriticalSection( &freetype_cs
);
6636 get_text_metrics(physdev
->font
, &tm
);
6637 size
->cy
= tm
.tmHeight
;
6639 for(idx
= 0; idx
< count
; idx
++) {
6640 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6641 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6643 if (! pnfit
|| ext
<= max_ext
) {
6653 LeaveCriticalSection( &freetype_cs
);
6654 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6658 /*************************************************************
6659 * freetype_GetFontData
6661 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6663 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6667 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6668 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6671 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6672 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6673 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6675 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6678 /*************************************************************
6679 * freetype_GetTextFace
6681 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6684 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6688 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6689 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6692 n
= strlenW(physdev
->font
->name
) + 1;
6695 lstrcpynW(str
, physdev
->font
->name
, count
);
6701 /*************************************************************
6702 * freetype_GetTextCharsetInfo
6704 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6706 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6710 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6711 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6713 if (fs
) *fs
= physdev
->font
->fs
;
6714 return physdev
->font
->charset
;
6717 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6719 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6720 struct list
*first_hfont
;
6724 EnterCriticalSection( &freetype_cs
);
6725 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6726 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6727 if(font
== linked_font
)
6728 *new_hfont
= dc
->hFont
;
6731 first_hfont
= list_head(&linked_font
->hfontlist
);
6732 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6734 LeaveCriticalSection( &freetype_cs
);
6738 /* Retrieve a list of supported Unicode ranges for a given font.
6739 * Can be called with NULL gs to calculate the buffer size. Returns
6740 * the number of ranges found.
6742 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6744 DWORD num_ranges
= 0;
6746 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6749 FT_ULong char_code
, char_code_prev
;
6752 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6754 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6755 face
->num_glyphs
, glyph_code
, char_code
);
6757 if (!glyph_code
) return 0;
6761 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6762 gs
->ranges
[0].cGlyphs
= 0;
6763 gs
->cGlyphsSupported
= 0;
6769 if (char_code
< char_code_prev
)
6771 ERR("expected increasing char code from FT_Get_Next_Char\n");
6774 if (char_code
- char_code_prev
> 1)
6779 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6780 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6781 gs
->cGlyphsSupported
++;
6786 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6787 gs
->cGlyphsSupported
++;
6789 char_code_prev
= char_code
;
6790 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6794 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6799 /*************************************************************
6800 * freetype_GetFontUnicodeRanges
6802 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6804 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6805 DWORD size
, num_ranges
;
6809 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6810 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6813 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6814 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6817 glyphset
->cbThis
= size
;
6818 glyphset
->cRanges
= num_ranges
;
6819 glyphset
->flAccel
= 0;
6824 /*************************************************************
6825 * freetype_FontIsLinked
6827 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6829 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6834 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6835 return dev
->funcs
->pFontIsLinked( dev
);
6839 EnterCriticalSection( &freetype_cs
);
6840 ret
= !list_empty(&physdev
->font
->child_fonts
);
6841 LeaveCriticalSection( &freetype_cs
);
6845 static BOOL
is_hinting_enabled(void)
6847 /* Use the >= 2.2.0 function if available */
6848 if(pFT_Get_TrueType_Engine_Type
)
6850 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6851 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6853 #ifdef FT_DRIVER_HAS_HINTER
6858 /* otherwise if we've been compiled with < 2.2.0 headers
6859 use the internal macro */
6860 mod
= pFT_Get_Module(library
, "truetype");
6861 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6869 static BOOL
is_subpixel_rendering_enabled( void )
6871 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6872 return pFT_Library_SetLcdFilter
&&
6873 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6879 /*************************************************************************
6880 * GetRasterizerCaps (GDI32.@)
6882 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6884 static int hinting
= -1;
6885 static int subpixel
= -1;
6889 hinting
= is_hinting_enabled();
6890 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6893 if ( subpixel
== -1 )
6895 subpixel
= is_subpixel_rendering_enabled();
6896 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6899 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6900 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6902 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6903 lprs
->nLanguageID
= 0;
6907 /*************************************************************
6908 * freetype_GdiRealizationInfo
6910 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
6912 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6913 realization_info_t
*info
= ptr
;
6917 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
6918 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
6921 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
6924 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
6927 info
->cache_num
= physdev
->font
->cache_num
;
6928 info
->unknown2
= -1;
6932 /*************************************************************************
6933 * Kerning support for TrueType fonts
6935 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6937 struct TT_kern_table
6943 struct TT_kern_subtable
6952 USHORT horizontal
: 1;
6954 USHORT cross_stream
: 1;
6955 USHORT override
: 1;
6956 USHORT reserved1
: 4;
6962 struct TT_format0_kern_subtable
6966 USHORT entrySelector
;
6977 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
6978 const struct TT_format0_kern_subtable
*tt_f0_ks
,
6979 const USHORT
*glyph_to_char
,
6980 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
6983 const struct TT_kern_pair
*tt_kern_pair
;
6985 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
6987 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
6989 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6990 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
6991 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
6993 if (!kern_pair
|| !cPairs
)
6996 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
6998 nPairs
= min(nPairs
, cPairs
);
7000 for (i
= 0; i
< nPairs
; i
++)
7002 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7003 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7004 /* this algorithm appears to better match what Windows does */
7005 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7006 if (kern_pair
->iKernAmount
< 0)
7008 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7009 kern_pair
->iKernAmount
-= font
->ppem
;
7011 else if (kern_pair
->iKernAmount
> 0)
7013 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7014 kern_pair
->iKernAmount
+= font
->ppem
;
7016 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7018 TRACE("left %u right %u value %d\n",
7019 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7023 TRACE("copied %u entries\n", nPairs
);
7027 /*************************************************************
7028 * freetype_GetKerningPairs
7030 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7034 const struct TT_kern_table
*tt_kern_table
;
7035 const struct TT_kern_subtable
*tt_kern_subtable
;
7037 USHORT
*glyph_to_char
;
7039 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7041 if (!(font
= physdev
->font
))
7043 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7044 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7048 EnterCriticalSection( &freetype_cs
);
7049 if (font
->total_kern_pairs
!= (DWORD
)-1)
7051 if (cPairs
&& kern_pair
)
7053 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7054 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7056 else cPairs
= font
->total_kern_pairs
;
7058 LeaveCriticalSection( &freetype_cs
);
7062 font
->total_kern_pairs
= 0;
7064 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7066 if (length
== GDI_ERROR
)
7068 TRACE("no kerning data in the font\n");
7069 LeaveCriticalSection( &freetype_cs
);
7073 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7076 WARN("Out of memory\n");
7077 LeaveCriticalSection( &freetype_cs
);
7081 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7083 /* build a glyph index to char code map */
7084 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7087 WARN("Out of memory allocating a glyph index to char code map\n");
7088 HeapFree(GetProcessHeap(), 0, buf
);
7089 LeaveCriticalSection( &freetype_cs
);
7093 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7099 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7101 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7102 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7106 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7108 /* FIXME: This doesn't match what Windows does: it does some fancy
7109 * things with duplicate glyph index to char code mappings, while
7110 * we just avoid overriding existing entries.
7112 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7113 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7115 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7122 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7123 for (n
= 0; n
<= 65535; n
++)
7124 glyph_to_char
[n
] = (USHORT
)n
;
7127 tt_kern_table
= buf
;
7128 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7129 TRACE("version %u, nTables %u\n",
7130 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7132 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7134 for (i
= 0; i
< nTables
; i
++)
7136 struct TT_kern_subtable tt_kern_subtable_copy
;
7138 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7139 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7140 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7142 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7143 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7144 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7146 /* According to the TrueType specification this is the only format
7147 * that will be properly interpreted by Windows and OS/2
7149 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7151 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7153 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7154 glyph_to_char
, NULL
, 0);
7155 font
->total_kern_pairs
+= new_chunk
;
7157 if (!font
->kern_pairs
)
7158 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7159 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7161 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7162 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7164 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7165 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7168 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7170 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7173 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7174 HeapFree(GetProcessHeap(), 0, buf
);
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 static const struct gdi_dc_funcs freetype_funcs
=
7189 NULL
, /* pAbortDoc */
7190 NULL
, /* pAbortPath */
7191 NULL
, /* pAlphaBlend */
7192 NULL
, /* pAngleArc */
7195 NULL
, /* pBeginPath */
7196 NULL
, /* pBlendImage */
7197 NULL
, /* pChoosePixelFormat */
7199 NULL
, /* pCloseFigure */
7200 NULL
, /* pCopyBitmap */
7201 NULL
, /* pCreateBitmap */
7202 NULL
, /* pCreateCompatibleDC */
7203 freetype_CreateDC
, /* pCreateDC */
7204 NULL
, /* pDeleteBitmap */
7205 freetype_DeleteDC
, /* pDeleteDC */
7206 NULL
, /* pDeleteObject */
7207 NULL
, /* pDescribePixelFormat */
7208 NULL
, /* pDeviceCapabilities */
7209 NULL
, /* pEllipse */
7211 NULL
, /* pEndPage */
7212 NULL
, /* pEndPath */
7213 freetype_EnumFonts
, /* pEnumFonts */
7214 NULL
, /* pEnumICMProfiles */
7215 NULL
, /* pExcludeClipRect */
7216 NULL
, /* pExtDeviceMode */
7217 NULL
, /* pExtEscape */
7218 NULL
, /* pExtFloodFill */
7219 NULL
, /* pExtSelectClipRgn */
7220 NULL
, /* pExtTextOut */
7221 NULL
, /* pFillPath */
7222 NULL
, /* pFillRgn */
7223 NULL
, /* pFlattenPath */
7224 freetype_FontIsLinked
, /* pFontIsLinked */
7225 NULL
, /* pFrameRgn */
7226 NULL
, /* pGdiComment */
7227 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7228 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7229 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7230 freetype_GetCharWidth
, /* pGetCharWidth */
7231 NULL
, /* pGetDeviceCaps */
7232 NULL
, /* pGetDeviceGammaRamp */
7233 freetype_GetFontData
, /* pGetFontData */
7234 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7235 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7236 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7237 NULL
, /* pGetICMProfile */
7238 NULL
, /* pGetImage */
7239 freetype_GetKerningPairs
, /* pGetKerningPairs */
7240 NULL
, /* pGetNearestColor */
7241 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7242 NULL
, /* pGetPixel */
7243 NULL
, /* pGetPixelFormat */
7244 NULL
, /* pGetSystemPaletteEntries */
7245 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7246 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7247 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7248 freetype_GetTextFace
, /* pGetTextFace */
7249 freetype_GetTextMetrics
, /* pGetTextMetrics */
7250 NULL
, /* pGradientFill */
7251 NULL
, /* pIntersectClipRect */
7252 NULL
, /* pInvertRgn */
7254 NULL
, /* pModifyWorldTransform */
7256 NULL
, /* pOffsetClipRgn */
7257 NULL
, /* pOffsetViewportOrg */
7258 NULL
, /* pOffsetWindowOrg */
7259 NULL
, /* pPaintRgn */
7262 NULL
, /* pPolyBezier */
7263 NULL
, /* pPolyBezierTo */
7264 NULL
, /* pPolyDraw */
7265 NULL
, /* pPolyPolygon */
7266 NULL
, /* pPolyPolyline */
7267 NULL
, /* pPolygon */
7268 NULL
, /* pPolyline */
7269 NULL
, /* pPolylineTo */
7270 NULL
, /* pPutImage */
7271 NULL
, /* pRealizeDefaultPalette */
7272 NULL
, /* pRealizePalette */
7273 NULL
, /* pRectangle */
7274 NULL
, /* pResetDC */
7275 NULL
, /* pRestoreDC */
7276 NULL
, /* pRoundRect */
7278 NULL
, /* pScaleViewportExt */
7279 NULL
, /* pScaleWindowExt */
7280 NULL
, /* pSelectBitmap */
7281 NULL
, /* pSelectBrush */
7282 NULL
, /* pSelectClipPath */
7283 freetype_SelectFont
, /* pSelectFont */
7284 NULL
, /* pSelectPalette */
7285 NULL
, /* pSelectPen */
7286 NULL
, /* pSetArcDirection */
7287 NULL
, /* pSetBkColor */
7288 NULL
, /* pSetBkMode */
7289 NULL
, /* pSetDCBrushColor */
7290 NULL
, /* pSetDCPenColor */
7291 NULL
, /* pSetDIBColorTable */
7292 NULL
, /* pSetDIBitsToDevice */
7293 NULL
, /* pSetDeviceClipping */
7294 NULL
, /* pSetDeviceGammaRamp */
7295 NULL
, /* pSetLayout */
7296 NULL
, /* pSetMapMode */
7297 NULL
, /* pSetMapperFlags */
7298 NULL
, /* pSetPixel */
7299 NULL
, /* pSetPixelFormat */
7300 NULL
, /* pSetPolyFillMode */
7301 NULL
, /* pSetROP2 */
7302 NULL
, /* pSetRelAbs */
7303 NULL
, /* pSetStretchBltMode */
7304 NULL
, /* pSetTextAlign */
7305 NULL
, /* pSetTextCharacterExtra */
7306 NULL
, /* pSetTextColor */
7307 NULL
, /* pSetTextJustification */
7308 NULL
, /* pSetViewportExt */
7309 NULL
, /* pSetViewportOrg */
7310 NULL
, /* pSetWindowExt */
7311 NULL
, /* pSetWindowOrg */
7312 NULL
, /* pSetWorldTransform */
7313 NULL
, /* pStartDoc */
7314 NULL
, /* pStartPage */
7315 NULL
, /* pStretchBlt */
7316 NULL
, /* pStretchDIBits */
7317 NULL
, /* pStrokeAndFillPath */
7318 NULL
, /* pStrokePath */
7319 NULL
, /* pSwapBuffers */
7320 NULL
, /* pUnrealizePalette */
7321 NULL
, /* pWidenPath */
7322 /* OpenGL not supported */
7325 #else /* HAVE_FREETYPE */
7327 /*************************************************************************/
7329 BOOL
WineEngInit(void)
7333 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7338 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7340 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7344 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7346 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7350 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7352 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7356 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7361 /*************************************************************************
7362 * GetRasterizerCaps (GDI32.@)
7364 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7366 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7368 lprs
->nLanguageID
= 0;
7372 #endif /* HAVE_FREETYPE */