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));
1923 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
1928 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
1930 /* reset dlen and vlen */
1934 HeapFree(GetProcessHeap(), 0, data
);
1935 HeapFree(GetProcessHeap(), 0, value
);
1940 static const WCHAR
*font_links_list
[] =
1942 Lucida_Sans_Unicode
,
1943 Microsoft_Sans_Serif
,
1947 static const struct font_links_defaults_list
1949 /* Keyed off substitution for "MS Shell Dlg" */
1950 const WCHAR
*shelldlg
;
1951 /* Maximum of four substitutes, plus terminating NULL pointer */
1952 const WCHAR
*substitutes
[5];
1953 } font_links_defaults_list
[] =
1955 /* Non East-Asian */
1956 { Tahoma
, /* FIXME unverified ordering */
1957 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
1959 /* Below lists are courtesy of
1960 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1964 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
1966 /* Chinese Simplified */
1968 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
1972 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
1974 /* Chinese Traditional */
1976 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
1981 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
1983 SYSTEM_LINKS
*font_link
;
1985 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1987 if(!strcmpiW(font_link
->font_name
, name
))
1994 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2007 SYSTEM_LINKS
*font_link
;
2009 memset(&fs
, 0, sizeof(fs
));
2010 psub
= get_font_subst(&font_subst_list
, name
, -1);
2011 /* Don't store fonts that are only substitutes for other fonts */
2014 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2018 font_link
= find_font_link(name
);
2019 if (font_link
== NULL
)
2021 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2022 font_link
->font_name
= strdupW(name
);
2023 list_init(&font_link
->links
);
2024 list_add_tail(&system_links
, &font_link
->entry
);
2027 for (i
= 0; values
[i
] != NULL
; i
++)
2029 CHILD_FONT
*child_font
;
2032 if (!strcmpiW(name
,value
))
2034 psub
= get_font_subst(&font_subst_list
, value
, -1);
2036 value
= psub
->to
.name
;
2037 family
= find_family_from_name(value
);
2041 /* Use first extant filename for this Family */
2042 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2046 file
= strrchr(face
->file
, '/');
2055 fileW
= towstr(CP_UNIXCP
, file
);
2057 face
= find_face_from_filename(fileW
, value
);
2060 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2064 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2065 child_font
->face
= face
;
2066 child_font
->font
= NULL
;
2067 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2068 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2069 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2070 list_add_tail(&font_link
->links
, &child_font
->entry
);
2072 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2073 HeapFree(GetProcessHeap(), 0, fileW
);
2076 family
= find_family_from_name(font_link
->font_name
);
2079 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2081 face
->fs_links
= fs
;
2088 /*************************************************************
2091 static BOOL
init_system_links(void)
2095 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2096 WCHAR
*value
, *data
;
2097 WCHAR
*entry
, *next
;
2098 SYSTEM_LINKS
*font_link
, *system_font_link
;
2099 CHILD_FONT
*child_font
;
2100 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2101 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2102 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2109 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2111 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2112 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2113 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2114 val_len
= max_val
+ 1;
2115 data_len
= max_data
;
2117 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2119 memset(&fs
, 0, sizeof(fs
));
2120 psub
= get_font_subst(&font_subst_list
, value
, -1);
2121 /* Don't store fonts that are only substitutes for other fonts */
2124 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2127 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2128 font_link
->font_name
= strdupW(value
);
2129 list_init(&font_link
->links
);
2130 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2133 CHILD_FONT
*child_font
;
2135 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2137 next
= entry
+ strlenW(entry
) + 1;
2139 face_name
= strchrW(entry
, ',');
2143 while(isspaceW(*face_name
))
2146 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2148 face_name
= psub
->to
.name
;
2150 face
= find_face_from_filename(entry
, face_name
);
2153 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2157 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2158 child_font
->face
= face
;
2159 child_font
->font
= NULL
;
2160 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2161 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2162 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2163 list_add_tail(&font_link
->links
, &child_font
->entry
);
2165 family
= find_family_from_name(font_link
->font_name
);
2168 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2170 face
->fs_links
= fs
;
2173 list_add_tail(&system_links
, &font_link
->entry
);
2175 val_len
= max_val
+ 1;
2176 data_len
= max_data
;
2179 HeapFree(GetProcessHeap(), 0, value
);
2180 HeapFree(GetProcessHeap(), 0, data
);
2185 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2187 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2191 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2193 const FontSubst
*psub2
;
2194 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2196 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2198 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2199 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2201 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2202 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2204 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2206 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2212 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2215 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2216 system_font_link
->font_name
= strdupW(System
);
2217 list_init(&system_font_link
->links
);
2218 memset(&fs
, 0, sizeof(fs
));
2220 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2223 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2224 child_font
->face
= face
;
2225 child_font
->font
= NULL
;
2226 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2227 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2228 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2229 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2231 font_link
= find_font_link(Tahoma
);
2232 if (font_link
!= NULL
)
2234 CHILD_FONT
*font_link_entry
;
2235 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2237 CHILD_FONT
*new_child
;
2238 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2239 new_child
->face
= font_link_entry
->face
;
2240 new_child
->font
= NULL
;
2241 fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2242 fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2243 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2246 family
= find_family_from_name(system_font_link
->font_name
);
2249 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2251 face
->fs_links
= fs
;
2254 list_add_tail(&system_links
, &system_font_link
->entry
);
2258 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2261 struct dirent
*dent
;
2262 char path
[MAX_PATH
];
2264 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2266 dir
= opendir(dirname
);
2268 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2271 while((dent
= readdir(dir
)) != NULL
) {
2272 struct stat statbuf
;
2274 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2277 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2279 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2281 if(stat(path
, &statbuf
) == -1)
2283 WARN("Can't stat %s\n", debugstr_a(path
));
2286 if(S_ISDIR(statbuf
.st_mode
))
2287 ReadFontDir(path
, external_fonts
);
2290 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2291 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2292 AddFontFileToList(path
, NULL
, NULL
, addfont_flags
);
2299 static void load_fontconfig_fonts(void)
2301 #ifdef SONAME_LIBFONTCONFIG
2302 void *fc_handle
= NULL
;
2311 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2313 TRACE("Wine cannot find the fontconfig library (%s).\n",
2314 SONAME_LIBFONTCONFIG
);
2317 #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;}
2318 LOAD_FUNCPTR(FcConfigGetCurrent
);
2319 LOAD_FUNCPTR(FcFontList
);
2320 LOAD_FUNCPTR(FcFontSetDestroy
);
2321 LOAD_FUNCPTR(FcInit
);
2322 LOAD_FUNCPTR(FcObjectSetAdd
);
2323 LOAD_FUNCPTR(FcObjectSetCreate
);
2324 LOAD_FUNCPTR(FcObjectSetDestroy
);
2325 LOAD_FUNCPTR(FcPatternCreate
);
2326 LOAD_FUNCPTR(FcPatternDestroy
);
2327 LOAD_FUNCPTR(FcPatternGetBool
);
2328 LOAD_FUNCPTR(FcPatternGetString
);
2331 if(!pFcInit()) return;
2333 config
= pFcConfigGetCurrent();
2334 pat
= pFcPatternCreate();
2335 os
= pFcObjectSetCreate();
2336 pFcObjectSetAdd(os
, FC_FILE
);
2337 pFcObjectSetAdd(os
, FC_SCALABLE
);
2338 fontset
= pFcFontList(config
, pat
, os
);
2339 if(!fontset
) return;
2340 for(i
= 0; i
< fontset
->nfont
; i
++) {
2343 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2345 TRACE("fontconfig: %s\n", file
);
2347 /* We're just interested in OT/TT fonts for now, so this hack just
2348 picks up the scalable fonts without extensions .pf[ab] to save time
2349 loading every other font */
2351 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2353 TRACE("not scalable\n");
2357 len
= strlen( file
);
2358 if(len
< 4) continue;
2359 ext
= &file
[ len
- 3 ];
2360 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2361 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2363 pFcFontSetDestroy(fontset
);
2364 pFcObjectSetDestroy(os
);
2365 pFcPatternDestroy(pat
);
2371 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2374 const char *data_dir
= wine_get_data_dir();
2376 if (!data_dir
) data_dir
= wine_get_build_dir();
2383 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2385 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2387 strcpy(unix_name
, data_dir
);
2388 strcat(unix_name
, "/fonts/");
2390 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2392 EnterCriticalSection( &freetype_cs
);
2393 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2394 LeaveCriticalSection( &freetype_cs
);
2395 HeapFree(GetProcessHeap(), 0, unix_name
);
2400 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2402 static const WCHAR slashW
[] = {'\\','\0'};
2404 WCHAR windowsdir
[MAX_PATH
];
2407 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2408 strcatW(windowsdir
, fontsW
);
2409 strcatW(windowsdir
, slashW
);
2410 strcatW(windowsdir
, file
);
2411 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2412 EnterCriticalSection( &freetype_cs
);
2413 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2414 LeaveCriticalSection( &freetype_cs
);
2415 HeapFree(GetProcessHeap(), 0, unixname
);
2420 static void load_system_fonts(void)
2423 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2424 const WCHAR
* const *value
;
2426 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2429 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2430 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2431 strcatW(windowsdir
, fontsW
);
2432 for(value
= SystemFontValues
; *value
; value
++) {
2433 dlen
= sizeof(data
);
2434 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2438 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2439 if((unixname
= wine_get_unix_file_name(pathW
))) {
2440 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2441 HeapFree(GetProcessHeap(), 0, unixname
);
2444 load_font_from_data_dir(data
);
2451 /*************************************************************
2453 * This adds registry entries for any externally loaded fonts
2454 * (fonts from fontconfig or FontDirs). It also deletes entries
2455 * of no longer existing fonts.
2458 static void update_reg_entries(void)
2460 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2465 struct list
*family_elem_ptr
, *face_elem_ptr
;
2467 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2468 static const WCHAR spaceW
[] = {' ', '\0'};
2471 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2472 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2473 ERR("Can't create Windows font reg key\n");
2477 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2478 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2479 ERR("Can't create Windows font reg key\n");
2483 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2484 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2485 ERR("Can't create external font reg key\n");
2489 /* enumerate the fonts and add external ones to the two keys */
2491 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2492 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2493 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2494 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2495 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2496 if(!face
->external
) continue;
2498 if (!(face
->ntmFlags
& NTM_REGULAR
))
2499 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2500 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2501 strcpyW(valueW
, family
->FamilyName
);
2502 if(len
!= len_fam
) {
2503 strcatW(valueW
, spaceW
);
2504 strcatW(valueW
, face
->StyleName
);
2506 strcatW(valueW
, TrueType
);
2508 file
= wine_get_dos_file_name(face
->file
);
2510 len
= strlenW(file
) + 1;
2513 if((path
= strrchr(face
->file
, '/')) == NULL
)
2517 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2519 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2520 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2522 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2523 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2524 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2526 HeapFree(GetProcessHeap(), 0, file
);
2527 HeapFree(GetProcessHeap(), 0, valueW
);
2531 if(external_key
) RegCloseKey(external_key
);
2532 if(win9x_key
) RegCloseKey(win9x_key
);
2533 if(winnt_key
) RegCloseKey(winnt_key
);
2537 static void delete_external_font_keys(void)
2539 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2540 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2544 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2545 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2546 ERR("Can't create Windows font reg key\n");
2550 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2551 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2552 ERR("Can't create Windows font reg key\n");
2556 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2557 ERR("Can't create external font reg key\n");
2561 /* Delete all external fonts added last time */
2563 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2564 &valuelen
, &datalen
, NULL
, NULL
);
2565 valuelen
++; /* returned value doesn't include room for '\0' */
2566 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2567 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2569 dlen
= datalen
* sizeof(WCHAR
);
2572 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2573 &dlen
) == ERROR_SUCCESS
) {
2575 RegDeleteValueW(winnt_key
, valueW
);
2576 RegDeleteValueW(win9x_key
, valueW
);
2577 /* reset dlen and vlen */
2581 HeapFree(GetProcessHeap(), 0, data
);
2582 HeapFree(GetProcessHeap(), 0, valueW
);
2584 /* Delete the old external fonts key */
2585 RegCloseKey(external_key
);
2586 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2589 if(win9x_key
) RegCloseKey(win9x_key
);
2590 if(winnt_key
) RegCloseKey(winnt_key
);
2593 /*************************************************************
2594 * WineEngAddFontResourceEx
2597 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2603 if (ft_handle
) /* do it only if we have freetype up and running */
2608 FIXME("Ignoring flags %x\n", flags
);
2610 if((unixname
= wine_get_unix_file_name(file
)))
2612 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2614 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2615 EnterCriticalSection( &freetype_cs
);
2616 ret
= AddFontFileToList(unixname
, NULL
, NULL
, addfont_flags
);
2617 LeaveCriticalSection( &freetype_cs
);
2618 HeapFree(GetProcessHeap(), 0, unixname
);
2620 if (!ret
&& !strchrW(file
, '\\')) {
2621 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2622 ret
= load_font_from_winfonts_dir(file
);
2624 /* Try in datadir/fonts (or builddir/fonts),
2625 * needed for Magic the Gathering Online
2627 ret
= load_font_from_data_dir(file
);
2634 /*************************************************************
2635 * WineEngAddFontMemResourceEx
2638 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2642 if (ft_handle
) /* do it only if we have freetype up and running */
2644 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2646 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2647 memcpy(pFontCopy
, pbFont
, cbFont
);
2649 EnterCriticalSection( &freetype_cs
);
2650 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2651 LeaveCriticalSection( &freetype_cs
);
2655 TRACE("AddFontToList failed\n");
2656 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2659 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2660 * For now return something unique but quite random
2662 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2663 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2670 /*************************************************************
2671 * WineEngRemoveFontResourceEx
2674 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2677 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2681 static const struct nls_update_font_list
2683 UINT ansi_cp
, oem_cp
;
2684 const char *oem
, *fixed
, *system
;
2685 const char *courier
, *serif
, *small
, *sserif
;
2686 /* these are for font substitutes */
2687 const char *shelldlg
, *tmsrmn
;
2688 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2692 const char *from
, *to
;
2693 } arial_0
, courier_new_0
, times_new_roman_0
;
2694 } nls_update_font_list
[] =
2696 /* Latin 1 (United States) */
2697 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2698 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2699 "Tahoma","Times New Roman",
2700 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2703 /* Latin 1 (Multilingual) */
2704 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2705 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2706 "Tahoma","Times New Roman", /* FIXME unverified */
2707 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2710 /* Eastern Europe */
2711 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2712 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2713 "Tahoma","Times New Roman", /* FIXME unverified */
2714 "Fixedsys,238", "System,238",
2715 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2716 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2717 { "Arial CE,0", "Arial,238" },
2718 { "Courier New CE,0", "Courier New,238" },
2719 { "Times New Roman CE,0", "Times New Roman,238" }
2722 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2723 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2724 "Tahoma","Times New Roman", /* FIXME unverified */
2725 "Fixedsys,204", "System,204",
2726 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2727 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2728 { "Arial Cyr,0", "Arial,204" },
2729 { "Courier New Cyr,0", "Courier New,204" },
2730 { "Times New Roman Cyr,0", "Times New Roman,204" }
2733 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2734 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2735 "Tahoma","Times New Roman", /* FIXME unverified */
2736 "Fixedsys,161", "System,161",
2737 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2738 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2739 { "Arial Greek,0", "Arial,161" },
2740 { "Courier New Greek,0", "Courier New,161" },
2741 { "Times New Roman Greek,0", "Times New Roman,161" }
2744 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2745 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2746 "Tahoma","Times New Roman", /* FIXME unverified */
2747 "Fixedsys,162", "System,162",
2748 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2749 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2750 { "Arial Tur,0", "Arial,162" },
2751 { "Courier New Tur,0", "Courier New,162" },
2752 { "Times New Roman Tur,0", "Times New Roman,162" }
2755 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2756 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2757 "Tahoma","Times New Roman", /* FIXME unverified */
2758 "Fixedsys,177", "System,177",
2759 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2760 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2764 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2765 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2766 "Tahoma","Times New Roman", /* FIXME unverified */
2767 "Fixedsys,178", "System,178",
2768 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2769 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2773 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2774 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2775 "Tahoma","Times New Roman", /* FIXME unverified */
2776 "Fixedsys,186", "System,186",
2777 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2778 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2779 { "Arial Baltic,0", "Arial,186" },
2780 { "Courier New Baltic,0", "Courier New,186" },
2781 { "Times New Roman Baltic,0", "Times New Roman,186" }
2784 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2785 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2786 "Tahoma","Times New Roman", /* FIXME unverified */
2787 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2791 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2792 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2793 "Tahoma","Times New Roman", /* FIXME unverified */
2794 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2798 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2799 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2800 "MS UI Gothic","MS Serif",
2801 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2804 /* Chinese Simplified */
2805 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2806 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2807 "SimSun", "NSimSun",
2808 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2812 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2813 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2815 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2818 /* Chinese Traditional */
2819 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2820 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2821 "PMingLiU", "MingLiU",
2822 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2827 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2829 return ( ansi_cp
== 932 /* CP932 for Japanese */
2830 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2831 || ansi_cp
== 949 /* CP949 for Korean */
2832 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2835 static inline HKEY
create_fonts_NT_registry_key(void)
2839 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2840 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2844 static inline HKEY
create_fonts_9x_registry_key(void)
2848 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2849 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2853 static inline HKEY
create_config_fonts_registry_key(void)
2857 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2858 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2862 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2864 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2865 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2866 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2867 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2870 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2873 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2875 RegDeleteValueA(hkey
, name
);
2878 static void update_font_info(void)
2880 char buf
[40], cpbuf
[40];
2883 UINT i
, ansi_cp
= 0, oem_cp
= 0;
2886 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
2889 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2890 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
2891 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
2892 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
2893 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
2895 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2896 if (is_dbcs_ansi_cp(ansi_cp
))
2897 use_default_fallback
= TRUE
;
2900 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
2902 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
2907 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
2909 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
2911 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
2914 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
2918 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
2919 nls_update_font_list
[i
].oem_cp
== oem_cp
)
2921 hkey
= create_config_fonts_registry_key();
2922 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
2923 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
2924 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
2927 hkey
= create_fonts_NT_registry_key();
2928 add_font_list(hkey
, &nls_update_font_list
[i
]);
2931 hkey
= create_fonts_9x_registry_key();
2932 add_font_list(hkey
, &nls_update_font_list
[i
]);
2935 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2937 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
2938 strlen(nls_update_font_list
[i
].shelldlg
)+1);
2939 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
2940 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
2942 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
2943 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
2944 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
2945 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
2946 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
2947 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
2948 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
2949 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
2951 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
2952 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
2953 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
2961 /* Delete the FontSubstitutes from other locales */
2962 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
2964 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
2965 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
2966 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
2972 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
2975 static BOOL
init_freetype(void)
2977 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
2980 "Wine cannot find the FreeType font library. To enable Wine to\n"
2981 "use TrueType fonts please install a version of FreeType greater than\n"
2982 "or equal to 2.0.5.\n"
2983 "http://www.freetype.org\n");
2987 #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;}
2989 LOAD_FUNCPTR(FT_Done_Face
)
2990 LOAD_FUNCPTR(FT_Get_Char_Index
)
2991 LOAD_FUNCPTR(FT_Get_First_Char
)
2992 LOAD_FUNCPTR(FT_Get_Module
)
2993 LOAD_FUNCPTR(FT_Get_Next_Char
)
2994 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
2995 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
2996 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
2997 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
2998 LOAD_FUNCPTR(FT_Init_FreeType
)
2999 LOAD_FUNCPTR(FT_Library_Version
)
3000 LOAD_FUNCPTR(FT_Load_Glyph
)
3001 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3002 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3003 #ifndef FT_MULFIX_INLINED
3004 LOAD_FUNCPTR(FT_MulFix
)
3006 LOAD_FUNCPTR(FT_New_Face
)
3007 LOAD_FUNCPTR(FT_New_Memory_Face
)
3008 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3009 LOAD_FUNCPTR(FT_Outline_Transform
)
3010 LOAD_FUNCPTR(FT_Outline_Translate
)
3011 LOAD_FUNCPTR(FT_Render_Glyph
)
3012 LOAD_FUNCPTR(FT_Select_Charmap
)
3013 LOAD_FUNCPTR(FT_Set_Charmap
)
3014 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3015 LOAD_FUNCPTR(FT_Vector_Transform
)
3016 LOAD_FUNCPTR(FT_Vector_Unit
)
3018 /* Don't warn if these ones are missing */
3019 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3020 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3021 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3024 if(pFT_Init_FreeType(&library
) != 0) {
3025 ERR("Can't init FreeType library\n");
3026 wine_dlclose(ft_handle
, NULL
, 0);
3030 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3032 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3033 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3034 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3035 ((FT_Version
.patch
) & 0x0000ff);
3037 font_driver
= &freetype_funcs
;
3042 "Wine cannot find certain functions that it needs inside the FreeType\n"
3043 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3044 "FreeType to at least version 2.1.4.\n"
3045 "http://www.freetype.org\n");
3046 wine_dlclose(ft_handle
, NULL
, 0);
3051 static void init_font_list(void)
3053 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3054 static const WCHAR pathW
[] = {'P','a','t','h',0};
3056 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3057 WCHAR windowsdir
[MAX_PATH
];
3060 const char *data_dir
;
3062 delete_external_font_keys();
3064 /* load the system bitmap fonts */
3065 load_system_fonts();
3067 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3068 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3069 strcatW(windowsdir
, fontsW
);
3070 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3072 ReadFontDir(unixname
, FALSE
);
3073 HeapFree(GetProcessHeap(), 0, unixname
);
3076 /* load the system truetype fonts */
3077 data_dir
= wine_get_data_dir();
3078 if (!data_dir
) data_dir
= wine_get_build_dir();
3079 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3081 strcpy(unixname
, data_dir
);
3082 strcat(unixname
, "/fonts/");
3083 ReadFontDir(unixname
, TRUE
);
3084 HeapFree(GetProcessHeap(), 0, unixname
);
3087 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3088 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3089 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3091 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3092 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3093 &hkey
) == ERROR_SUCCESS
)
3095 LPWSTR data
, valueW
;
3096 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3097 &valuelen
, &datalen
, NULL
, NULL
);
3099 valuelen
++; /* returned value doesn't include room for '\0' */
3100 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3101 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3104 dlen
= datalen
* sizeof(WCHAR
);
3106 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3107 &dlen
) == ERROR_SUCCESS
)
3109 if(data
[0] && (data
[1] == ':'))
3111 if((unixname
= wine_get_unix_file_name(data
)))
3113 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3114 HeapFree(GetProcessHeap(), 0, unixname
);
3117 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3119 WCHAR pathW
[MAX_PATH
];
3120 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3123 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3124 if((unixname
= wine_get_unix_file_name(pathW
)))
3126 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3127 HeapFree(GetProcessHeap(), 0, unixname
);
3130 load_font_from_data_dir(data
);
3132 /* reset dlen and vlen */
3137 HeapFree(GetProcessHeap(), 0, data
);
3138 HeapFree(GetProcessHeap(), 0, valueW
);
3142 load_fontconfig_fonts();
3144 /* then look in any directories that we've specified in the config file */
3145 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3146 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3152 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3154 len
+= sizeof(WCHAR
);
3155 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3156 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3158 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3159 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3160 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3161 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3165 LPSTR next
= strchr( ptr
, ':' );
3166 if (next
) *next
++ = 0;
3167 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3168 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3170 strcpy( unixname
, home
);
3171 strcat( unixname
, ptr
+ 1 );
3172 ReadFontDir( unixname
, TRUE
);
3173 HeapFree( GetProcessHeap(), 0, unixname
);
3176 ReadFontDir( ptr
, TRUE
);
3179 HeapFree( GetProcessHeap(), 0, valueA
);
3181 HeapFree( GetProcessHeap(), 0, valueW
);
3187 /* Mac default font locations. */
3188 ReadFontDir( "/Library/Fonts", TRUE
);
3189 ReadFontDir( "/Network/Library/Fonts", TRUE
);
3190 ReadFontDir( "/System/Library/Fonts", TRUE
);
3191 if ((home
= getenv( "HOME" )))
3193 unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(home
)+15 );
3194 strcpy( unixname
, home
);
3195 strcat( unixname
, "/Library/Fonts" );
3196 ReadFontDir( unixname
, TRUE
);
3197 HeapFree( GetProcessHeap(), 0, unixname
);
3202 static BOOL
move_to_front(const WCHAR
*name
)
3204 Family
*family
, *cursor2
;
3205 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3207 if(!strcmpiW(family
->FamilyName
, name
))
3209 list_remove(&family
->entry
);
3210 list_add_head(&font_list
, &family
->entry
);
3217 static BOOL
set_default(const WCHAR
**name_list
)
3221 if (move_to_front(*name_list
)) return TRUE
;
3228 static void reorder_font_list(void)
3230 set_default( default_serif_list
);
3231 set_default( default_fixed_list
);
3232 set_default( default_sans_list
);
3235 /*************************************************************
3238 * Initialize FreeType library and create a list of available faces
3240 BOOL
WineEngInit(void)
3242 HKEY hkey_font_cache
;
3246 /* update locale dependent font info in registry */
3249 if(!init_freetype()) return FALSE
;
3251 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3253 ERR("Failed to create font mutex\n");
3256 WaitForSingleObject(font_mutex
, INFINITE
);
3258 create_font_cache_key(&hkey_font_cache
, &disposition
);
3260 if(disposition
== REG_CREATED_NEW_KEY
)
3263 load_font_list_from_cache(hkey_font_cache
);
3265 RegCloseKey(hkey_font_cache
);
3267 reorder_font_list();
3274 if(disposition
== REG_CREATED_NEW_KEY
)
3275 update_reg_entries();
3277 init_system_links();
3279 ReleaseMutex(font_mutex
);
3284 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3287 TT_HoriHeader
*pHori
;
3291 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3292 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3294 if(height
== 0) height
= 16;
3296 /* Calc. height of EM square:
3298 * For +ve lfHeight we have
3299 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3300 * Re-arranging gives:
3301 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3303 * For -ve lfHeight we have
3305 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3306 * with il = winAscent + winDescent - units_per_em]
3311 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3312 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3313 pHori
->Ascender
- pHori
->Descender
);
3315 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3316 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3324 static struct font_mapping
*map_font_file( const char *name
)
3326 struct font_mapping
*mapping
;
3330 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3331 if (fstat( fd
, &st
) == -1) goto error
;
3333 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3335 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3337 mapping
->refcount
++;
3342 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3345 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3348 if (mapping
->data
== MAP_FAILED
)
3350 HeapFree( GetProcessHeap(), 0, mapping
);
3353 mapping
->refcount
= 1;
3354 mapping
->dev
= st
.st_dev
;
3355 mapping
->ino
= st
.st_ino
;
3356 mapping
->size
= st
.st_size
;
3357 list_add_tail( &mappings_list
, &mapping
->entry
);
3365 static void unmap_font_file( struct font_mapping
*mapping
)
3367 if (!--mapping
->refcount
)
3369 list_remove( &mapping
->entry
);
3370 munmap( mapping
->data
, mapping
->size
);
3371 HeapFree( GetProcessHeap(), 0, mapping
);
3375 static LONG
load_VDMX(GdiFont
*, LONG
);
3377 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3384 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3388 if (!(font
->mapping
= map_font_file( face
->file
)))
3390 WARN("failed to map %s\n", debugstr_a(face
->file
));
3393 data_ptr
= font
->mapping
->data
;
3394 data_size
= font
->mapping
->size
;
3398 data_ptr
= face
->font_data_ptr
;
3399 data_size
= face
->font_data_size
;
3402 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3404 ERR("FT_New_Face rets %d\n", err
);
3408 /* set it here, as load_VDMX needs it */
3409 font
->ft_face
= ft_face
;
3411 if(FT_IS_SCALABLE(ft_face
)) {
3412 /* load the VDMX table if we have one */
3413 font
->ppem
= load_VDMX(font
, height
);
3415 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3416 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3418 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3419 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3421 font
->ppem
= height
;
3422 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3423 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3429 static int get_nearest_charset(Face
*face
, int *cp
)
3431 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3432 a single face with the requested charset. The idea is to check if
3433 the selected font supports the current ANSI codepage, if it does
3434 return the corresponding charset, else return the first charset */
3437 int acp
= GetACP(), i
;
3441 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3442 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3443 return csi
.ciCharset
;
3445 for(i
= 0; i
< 32; i
++) {
3447 if(face
->fs
.fsCsb
[0] & fs0
) {
3448 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3450 return csi
.ciCharset
;
3453 FIXME("TCI failing on %x\n", fs0
);
3457 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3458 face
->fs
.fsCsb
[0], face
->file
);
3460 return DEFAULT_CHARSET
;
3463 static GdiFont
*alloc_font(void)
3465 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3467 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3468 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3470 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3471 ret
->total_kern_pairs
= (DWORD
)-1;
3472 ret
->kern_pairs
= NULL
;
3473 list_init(&ret
->hfontlist
);
3474 list_init(&ret
->child_fonts
);
3478 static void free_font(GdiFont
*font
)
3480 struct list
*cursor
, *cursor2
;
3483 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3485 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3486 list_remove(cursor
);
3488 free_font(child
->font
);
3489 HeapFree(GetProcessHeap(), 0, child
);
3492 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3494 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3495 DeleteObject(hfontlist
->hfont
);
3496 list_remove(&hfontlist
->entry
);
3497 HeapFree(GetProcessHeap(), 0, hfontlist
);
3500 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3501 if (font
->mapping
) unmap_font_file( font
->mapping
);
3502 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3503 HeapFree(GetProcessHeap(), 0, font
->potm
);
3504 HeapFree(GetProcessHeap(), 0, font
->name
);
3505 for (i
= 0; i
< font
->gmsize
; i
++)
3506 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3507 HeapFree(GetProcessHeap(), 0, font
->gm
);
3508 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3509 HeapFree(GetProcessHeap(), 0, font
);
3513 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3515 FT_Face ft_face
= font
->ft_face
;
3519 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3526 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3528 /* make sure value of len is the value freetype says it needs */
3531 FT_ULong needed
= 0;
3532 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3533 if( !err
&& needed
< len
) len
= needed
;
3535 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3538 TRACE("Can't find table %c%c%c%c\n",
3539 /* bytes were reversed */
3540 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3541 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3547 /*************************************************************
3550 * load the vdmx entry for the specified height
3553 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3554 ( ( (FT_ULong)_x4 << 24 ) | \
3555 ( (FT_ULong)_x3 << 16 ) | \
3556 ( (FT_ULong)_x2 << 8 ) | \
3559 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3574 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3578 BYTE devXRatio
, devYRatio
;
3579 USHORT numRecs
, numRatios
;
3580 DWORD result
, offset
= -1;
3584 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3586 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3589 /* FIXME: need the real device aspect ratio */
3593 numRecs
= GET_BE_WORD(hdr
[1]);
3594 numRatios
= GET_BE_WORD(hdr
[2]);
3596 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3597 for(i
= 0; i
< numRatios
; i
++) {
3600 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3601 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3604 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3606 if((ratio
.xRatio
== 0 &&
3607 ratio
.yStartRatio
== 0 &&
3608 ratio
.yEndRatio
== 0) ||
3609 (devXRatio
== ratio
.xRatio
&&
3610 devYRatio
>= ratio
.yStartRatio
&&
3611 devYRatio
<= ratio
.yEndRatio
))
3613 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3614 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3615 offset
= GET_BE_WORD(tmp
);
3621 FIXME("No suitable ratio found\n");
3625 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3627 BYTE startsz
, endsz
;
3630 recs
= GET_BE_WORD(group
.recs
);
3631 startsz
= group
.startsz
;
3632 endsz
= group
.endsz
;
3634 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3636 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3637 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3638 if(result
== GDI_ERROR
) {
3639 FIXME("Failed to retrieve vTable\n");
3644 for(i
= 0; i
< recs
; i
++) {
3645 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3646 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3647 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3649 if(yMax
+ -yMin
== height
) {
3652 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3655 if(yMax
+ -yMin
> height
) {
3658 goto end
; /* failed */
3660 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3661 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3662 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3663 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3669 TRACE("ppem not found for height %d\n", height
);
3673 HeapFree(GetProcessHeap(), 0, vTable
);
3679 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3681 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3682 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3683 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3684 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3685 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3688 static void calc_hash(FONT_DESC
*pfd
)
3690 DWORD hash
= 0, *ptr
, two_chars
;
3694 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3696 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3698 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3700 pwc
= (WCHAR
*)&two_chars
;
3702 *pwc
= toupperW(*pwc
);
3704 *pwc
= toupperW(*pwc
);
3708 hash
^= !pfd
->can_use_bitmap
;
3713 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3718 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3722 fd
.can_use_bitmap
= can_use_bitmap
;
3725 /* try the child list */
3726 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3727 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3728 if(!fontcmp(ret
, &fd
)) {
3729 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3730 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3731 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3732 if(hflist
->hfont
== hfont
)
3738 /* try the in-use list */
3739 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3740 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3741 if(!fontcmp(ret
, &fd
)) {
3742 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3743 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3744 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3745 if(hflist
->hfont
== hfont
)
3748 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3749 hflist
->hfont
= hfont
;
3750 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3755 /* then the unused list */
3756 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3757 while(font_elem_ptr
) {
3758 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3759 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3760 if(!fontcmp(ret
, &fd
)) {
3761 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3762 assert(list_empty(&ret
->hfontlist
));
3763 TRACE("Found %p in unused list\n", ret
);
3764 list_remove(&ret
->entry
);
3765 list_add_head(&gdi_font_list
, &ret
->entry
);
3766 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3767 hflist
->hfont
= hfont
;
3768 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3775 static void add_to_cache(GdiFont
*font
)
3777 static DWORD cache_num
= 1;
3779 font
->cache_num
= cache_num
++;
3780 list_add_head(&gdi_font_list
, &font
->entry
);
3783 /*************************************************************
3784 * create_child_font_list
3786 static BOOL
create_child_font_list(GdiFont
*font
)
3789 SYSTEM_LINKS
*font_link
;
3790 CHILD_FONT
*font_link_entry
, *new_child
;
3794 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3795 font_name
= psub
? psub
->to
.name
: font
->name
;
3796 font_link
= find_font_link(font_name
);
3797 if (font_link
!= NULL
)
3799 TRACE("found entry in system list\n");
3800 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3802 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3803 new_child
->face
= font_link_entry
->face
;
3804 new_child
->font
= NULL
;
3805 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3806 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3811 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3812 * Sans Serif. This is how asian windows get default fallbacks for fonts
3814 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3815 font
->charset
!= OEM_CHARSET
&&
3816 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3818 font_link
= find_font_link(szDefaultFallbackLink
);
3819 if (font_link
!= NULL
)
3821 TRACE("found entry in default fallback list\n");
3822 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3824 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3825 new_child
->face
= font_link_entry
->face
;
3826 new_child
->font
= NULL
;
3827 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3828 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3837 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3839 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3841 if (pFT_Set_Charmap
)
3844 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3846 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3848 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3850 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3852 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3853 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3855 switch (ft_face
->charmaps
[i
]->platform_id
)
3858 cmap_def
= ft_face
->charmaps
[i
];
3860 case 0: /* Apple Unicode */
3861 cmap0
= ft_face
->charmaps
[i
];
3863 case 1: /* Macintosh */
3864 cmap1
= ft_face
->charmaps
[i
];
3867 cmap2
= ft_face
->charmaps
[i
];
3869 case 3: /* Microsoft */
3870 cmap3
= ft_face
->charmaps
[i
];
3875 if (cmap3
) /* prefer Microsoft cmap table */
3876 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3878 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3880 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3882 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3884 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3886 return ft_err
== FT_Err_Ok
;
3889 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
3893 /*************************************************************
3896 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
3897 LPCWSTR output
, const DEVMODEW
*devmode
)
3899 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
3901 if (!physdev
) return FALSE
;
3902 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
3907 /*************************************************************
3910 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
3912 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3913 HeapFree( GetProcessHeap(), 0, physdev
);
3918 /*************************************************************
3919 * freetype_SelectFont
3921 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
3923 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
3925 Face
*face
, *best
, *best_bitmap
;
3926 Family
*family
, *last_resort_family
;
3927 struct list
*family_elem_ptr
, *face_elem_ptr
;
3928 INT height
, width
= 0;
3929 unsigned int score
= 0, new_score
;
3930 signed int diff
= 0, newdiff
;
3931 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
3936 FontSubst
*psub
= NULL
;
3937 DC
*dc
= get_dc_ptr( dev
->hdc
);
3939 if (!hfont
) /* notification that the font has been changed by another driver */
3942 physdev
->font
= NULL
;
3943 release_dc_ptr( dc
);
3947 GetObjectW( hfont
, sizeof(lf
), &lf
);
3948 lf
.lfWidth
= abs(lf
.lfWidth
);
3950 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
3952 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3953 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
3954 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
3957 if(dc
->GraphicsMode
== GM_ADVANCED
)
3959 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
3960 /* Try to avoid not necessary glyph transformations */
3961 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
3963 lf
.lfHeight
*= fabs(dcmat
.eM11
);
3964 lf
.lfWidth
*= fabs(dcmat
.eM11
);
3965 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3970 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3971 font scaling abilities. */
3972 dcmat
.eM11
= dcmat
.eM22
= 1.0;
3973 dcmat
.eM21
= dcmat
.eM12
= 0;
3974 if (dc
->vport2WorldValid
)
3976 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
3977 lf
.lfOrientation
= -lf
.lfOrientation
;
3978 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
3979 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
3983 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
3984 dcmat
.eM21
, dcmat
.eM22
);
3987 EnterCriticalSection( &freetype_cs
);
3989 /* check the cache first */
3990 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
3991 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
3995 if(list_empty(&font_list
)) /* No fonts installed */
3997 TRACE("No fonts installed\n");
4001 TRACE("not in cache\n");
4004 ret
->font_desc
.matrix
= dcmat
;
4005 ret
->font_desc
.lf
= lf
;
4006 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4007 calc_hash(&ret
->font_desc
);
4008 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4009 hflist
->hfont
= hfont
;
4010 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4012 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4013 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4014 original value lfCharSet. Note this is a special case for
4015 Symbol and doesn't happen at least for "Wingdings*" */
4017 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4018 lf
.lfCharSet
= SYMBOL_CHARSET
;
4020 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4021 switch(lf
.lfCharSet
) {
4022 case DEFAULT_CHARSET
:
4023 csi
.fs
.fsCsb
[0] = 0;
4026 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4027 csi
.fs
.fsCsb
[0] = 0;
4033 if(lf
.lfFaceName
[0] != '\0') {
4034 SYSTEM_LINKS
*font_link
;
4035 CHILD_FONT
*font_link_entry
;
4036 LPWSTR FaceName
= lf
.lfFaceName
;
4038 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4041 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4042 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4043 if (psub
->to
.charset
!= -1)
4044 lf
.lfCharSet
= psub
->to
.charset
;
4047 /* We want a match on name and charset or just name if
4048 charset was DEFAULT_CHARSET. If the latter then
4049 we fixup the returned charset later in get_nearest_charset
4050 where we'll either use the charset of the current ansi codepage
4051 or if that's unavailable the first charset that the font supports.
4053 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4054 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4055 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4056 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4058 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4059 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4060 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
4061 if(face
->scalable
|| can_use_bitmap
)
4067 /* Search by full face name. */
4068 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4069 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4070 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4071 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4072 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4073 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]))
4075 if(face
->scalable
|| can_use_bitmap
)
4082 * Try check the SystemLink list first for a replacement font.
4083 * We may find good replacements there.
4085 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4087 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4088 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4090 TRACE("found entry in system list\n");
4091 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4093 face
= font_link_entry
->face
;
4094 family
= face
->family
;
4095 if(csi
.fs
.fsCsb
[0] &
4096 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
4098 if(face
->scalable
|| can_use_bitmap
)
4106 psub
= NULL
; /* substitution is no more relevant */
4108 /* If requested charset was DEFAULT_CHARSET then try using charset
4109 corresponding to the current ansi codepage */
4110 if (!csi
.fs
.fsCsb
[0])
4113 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4114 FIXME("TCI failed on codepage %d\n", acp
);
4115 csi
.fs
.fsCsb
[0] = 0;
4117 lf
.lfCharSet
= csi
.ciCharset
;
4120 want_vertical
= (lf
.lfFaceName
[0] == '@');
4122 /* Face families are in the top 4 bits of lfPitchAndFamily,
4123 so mask with 0xF0 before testing */
4125 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4126 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4127 strcpyW(lf
.lfFaceName
, defFixed
);
4128 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4129 strcpyW(lf
.lfFaceName
, defSerif
);
4130 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4131 strcpyW(lf
.lfFaceName
, defSans
);
4133 strcpyW(lf
.lfFaceName
, defSans
);
4134 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4135 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4136 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4137 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4138 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4139 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
4140 if(face
->scalable
|| can_use_bitmap
)
4146 last_resort_family
= NULL
;
4147 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4148 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4149 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4150 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4151 if(face
->vertical
== want_vertical
&&
4152 (csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))) {
4155 if(can_use_bitmap
&& !last_resort_family
)
4156 last_resort_family
= family
;
4161 if(last_resort_family
) {
4162 family
= last_resort_family
;
4163 csi
.fs
.fsCsb
[0] = 0;
4167 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4168 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4169 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4170 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4171 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4172 csi
.fs
.fsCsb
[0] = 0;
4173 WARN("just using first face for now\n");
4176 if(can_use_bitmap
&& !last_resort_family
)
4177 last_resort_family
= family
;
4180 if(!last_resort_family
) {
4181 FIXME("can't find a single appropriate font - bailing\n");
4187 WARN("could only find a bitmap font - this will probably look awful!\n");
4188 family
= last_resort_family
;
4189 csi
.fs
.fsCsb
[0] = 0;
4192 it
= lf
.lfItalic
? 1 : 0;
4193 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4195 height
= lf
.lfHeight
;
4197 face
= best
= best_bitmap
= NULL
;
4198 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
4200 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
4204 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4205 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4206 new_score
= (italic
^ it
) + (bold
^ bd
);
4207 if(!best
|| new_score
<= score
)
4209 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4210 italic
, bold
, it
, bd
);
4213 if(best
->scalable
&& score
== 0) break;
4217 newdiff
= height
- (signed int)(best
->size
.height
);
4219 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4220 if(!best_bitmap
|| new_score
< score
||
4221 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4223 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4226 if(score
== 0 && diff
== 0) break;
4233 face
= best
->scalable
? best
: best_bitmap
;
4234 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4235 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4238 height
= lf
.lfHeight
;
4242 if(csi
.fs
.fsCsb
[0]) {
4243 ret
->charset
= lf
.lfCharSet
;
4244 ret
->codepage
= csi
.ciACP
;
4247 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
4249 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4250 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4252 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4254 if(!face
->scalable
) {
4255 /* Windows uses integer scaling factors for bitmap fonts */
4256 INT scale
, scaled_height
;
4257 GdiFont
*cachedfont
;
4259 /* FIXME: rotation of bitmap fonts is ignored */
4260 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4262 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4263 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4264 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4265 /* As we changed the matrix, we need to search the cache for the font again,
4266 * otherwise we might explode the cache. */
4267 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4268 TRACE("Found cached font after non-scalable matrix rescale!\n");
4273 calc_hash(&ret
->font_desc
);
4275 if (height
!= 0) height
= diff
;
4276 height
+= face
->size
.height
;
4278 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4279 scaled_height
= scale
* face
->size
.height
;
4280 /* Only jump to the next height if the difference <= 25% original height */
4281 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4282 /* The jump between unscaled and doubled is delayed by 1 */
4283 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4284 ret
->scale_y
= scale
;
4286 width
= face
->size
.x_ppem
>> 6;
4287 height
= face
->size
.y_ppem
>> 6;
4291 TRACE("font scale y: %f\n", ret
->scale_y
);
4293 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4302 ret
->ntmFlags
= face
->ntmFlags
;
4304 if (ret
->charset
== SYMBOL_CHARSET
&&
4305 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4308 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4312 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4315 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4316 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4317 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4318 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4319 create_child_font_list(ret
);
4321 if (face
->vertical
) /* We need to try to load the GSUB table */
4323 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4324 if (length
!= GDI_ERROR
)
4326 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4327 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4328 TRACE("Loaded GSUB table of %i bytes\n",length
);
4332 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4339 physdev
->font
= ret
;
4341 LeaveCriticalSection( &freetype_cs
);
4342 release_dc_ptr( dc
);
4343 return ret
? hfont
: 0;
4346 static void dump_gdi_font_list(void)
4349 struct list
*elem_ptr
;
4351 TRACE("---------- gdiFont Cache ----------\n");
4352 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4353 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4354 TRACE("gdiFont=%p %s %d\n",
4355 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4358 TRACE("---------- Unused gdiFont Cache ----------\n");
4359 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4360 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4361 TRACE("gdiFont=%p %s %d\n",
4362 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4365 TRACE("---------- Child gdiFont Cache ----------\n");
4366 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4367 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4368 TRACE("gdiFont=%p %s %d\n",
4369 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4373 /*************************************************************
4374 * WineEngDestroyFontInstance
4376 * free the gdiFont associated with this handle
4379 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4384 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4388 EnterCriticalSection( &freetype_cs
);
4390 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4392 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4393 while(hfontlist_elem_ptr
) {
4394 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4395 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4396 if(hflist
->hfont
== handle
) {
4397 TRACE("removing child font %p from child list\n", gdiFont
);
4398 list_remove(&gdiFont
->entry
);
4399 LeaveCriticalSection( &freetype_cs
);
4405 TRACE("destroying hfont=%p\n", handle
);
4407 dump_gdi_font_list();
4409 font_elem_ptr
= list_head(&gdi_font_list
);
4410 while(font_elem_ptr
) {
4411 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4412 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4414 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4415 while(hfontlist_elem_ptr
) {
4416 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4417 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4418 if(hflist
->hfont
== handle
) {
4419 list_remove(&hflist
->entry
);
4420 HeapFree(GetProcessHeap(), 0, hflist
);
4424 if(list_empty(&gdiFont
->hfontlist
)) {
4425 TRACE("Moving to Unused list\n");
4426 list_remove(&gdiFont
->entry
);
4427 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4432 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4433 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4434 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4435 while(font_elem_ptr
) {
4436 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4437 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4438 TRACE("freeing %p\n", gdiFont
);
4439 list_remove(&gdiFont
->entry
);
4442 LeaveCriticalSection( &freetype_cs
);
4446 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4453 id
+= IDS_FIRST_SCRIPT
;
4454 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4455 if (!rsrc
) return 0;
4456 hMem
= LoadResource( gdi32_module
, rsrc
);
4457 if (!hMem
) return 0;
4459 p
= LockResource( hMem
);
4461 while (id
--) p
+= *p
+ 1;
4463 i
= min(LF_FACESIZE
- 1, *p
);
4464 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4470 /***************************************************
4471 * create_enum_charset_list
4473 * This function creates charset enumeration list because in DEFAULT_CHARSET
4474 * case, the ANSI codepage's charset takes precedence over other charsets.
4475 * This function works as a filter other than DEFAULT_CHARSET case.
4477 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4482 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4483 csi
.fs
.fsCsb
[0] != 0) {
4484 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4485 list
->element
[n
].charset
= csi
.ciCharset
;
4486 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4489 else { /* charset is DEFAULT_CHARSET or invalid. */
4492 /* Set the current codepage's charset as the first element. */
4494 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4495 csi
.fs
.fsCsb
[0] != 0) {
4496 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4497 list
->element
[n
].charset
= csi
.ciCharset
;
4498 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4502 /* Fill out left elements. */
4503 for (i
= 0; i
< 32; i
++) {
4505 fs
.fsCsb
[0] = 1L << i
;
4507 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4508 continue; /* skip, already added. */
4509 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4510 continue; /* skip, this is an invalid fsCsb bit. */
4512 list
->element
[n
].mask
= fs
.fsCsb
[0];
4513 list
->element
[n
].charset
= csi
.ciCharset
;
4514 load_script_name( i
, list
->element
[n
].name
);
4523 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4524 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4529 if (face
->cached_enum_data
)
4532 *pelf
= face
->cached_enum_data
->elf
;
4533 *pntm
= face
->cached_enum_data
->ntm
;
4534 *ptype
= face
->cached_enum_data
->type
;
4538 font
= alloc_font();
4540 if(face
->scalable
) {
4541 height
= -2048; /* 2048 is the most common em size */
4544 height
= face
->size
.y_ppem
>> 6;
4545 width
= face
->size
.x_ppem
>> 6;
4547 font
->scale_y
= 1.0;
4549 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4555 font
->name
= strdupW(face
->family
->FamilyName
);
4556 font
->ntmFlags
= face
->ntmFlags
;
4558 if (get_outline_text_metrics(font
))
4560 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4562 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4564 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4565 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4567 lstrcpynW(pelf
->elfFullName
,
4568 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4570 lstrcpynW(pelf
->elfStyle
,
4571 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4576 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4578 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4580 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4582 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4584 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4585 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4588 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4589 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4590 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4591 pntm
->ntmFontSig
= face
->fs
;
4593 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4595 pelf
->elfLogFont
.lfEscapement
= 0;
4596 pelf
->elfLogFont
.lfOrientation
= 0;
4597 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4598 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4599 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4600 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4601 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4602 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4603 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4604 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4605 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4606 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4607 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4610 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4611 *ptype
|= TRUETYPE_FONTTYPE
;
4612 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4613 *ptype
|= DEVICE_FONTTYPE
;
4614 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4615 *ptype
|= RASTER_FONTTYPE
;
4617 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4618 if (face
->cached_enum_data
)
4620 face
->cached_enum_data
->elf
= *pelf
;
4621 face
->cached_enum_data
->ntm
= *pntm
;
4622 face
->cached_enum_data
->type
= *ptype
;
4628 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4630 struct list
*face_elem_ptr
;
4632 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4634 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
)
4636 static const WCHAR spaceW
[] = { ' ',0 };
4637 WCHAR full_family_name
[LF_FULLFACESIZE
];
4638 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4640 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4642 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4643 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4647 strcpyW(full_family_name
, family
->FamilyName
);
4648 strcatW(full_family_name
, spaceW
);
4649 strcatW(full_family_name
, face
->StyleName
);
4650 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4656 static BOOL
face_matches(Face
*face
, const LOGFONTW
*lf
)
4658 static const WCHAR spaceW
[] = { ' ',0 };
4659 WCHAR full_family_name
[LF_FULLFACESIZE
];
4661 if (!strcmpiW(lf
->lfFaceName
, face
->family
->FamilyName
)) return TRUE
;
4663 if (strlenW(face
->family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4665 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4666 debugstr_w(face
->family
->FamilyName
), debugstr_w(face
->StyleName
));
4670 strcpyW(full_family_name
, face
->family
->FamilyName
);
4671 strcatW(full_family_name
, spaceW
);
4672 strcatW(full_family_name
, face
->StyleName
);
4673 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4676 static BOOL
enum_face_charsets(Face
*face
, struct enum_charset_list
*list
,
4677 FONTENUMPROCW proc
, LPARAM lparam
)
4680 NEWTEXTMETRICEXW ntm
;
4684 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4685 for(i
= 0; i
< list
->total
; i
++) {
4686 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4687 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4688 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4689 i
= list
->total
; /* break out of loop after enumeration */
4690 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4693 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4694 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4695 if (!elf
.elfScript
[0])
4696 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4698 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4699 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4700 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4701 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4702 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4703 ntm
.ntmTm
.ntmFlags
);
4704 /* release section before callback (FIXME) */
4705 LeaveCriticalSection( &freetype_cs
);
4706 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4707 EnterCriticalSection( &freetype_cs
);
4712 /*************************************************************
4713 * freetype_EnumFonts
4715 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4719 struct list
*family_elem_ptr
, *face_elem_ptr
;
4721 struct enum_charset_list enum_charsets
;
4725 lf
.lfCharSet
= DEFAULT_CHARSET
;
4726 lf
.lfPitchAndFamily
= 0;
4727 lf
.lfFaceName
[0] = 0;
4731 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4733 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4736 EnterCriticalSection( &freetype_cs
);
4737 if(plf
->lfFaceName
[0]) {
4739 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4742 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4743 debugstr_w(psub
->to
.name
));
4745 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4749 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4750 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4751 if(family_matches(family
, plf
)) {
4752 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4753 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4754 if (!face_matches(face
, plf
)) continue;
4755 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4760 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4761 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4762 face_elem_ptr
= list_head(&family
->faces
);
4763 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4764 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4767 LeaveCriticalSection( &freetype_cs
);
4771 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4773 pt
->x
.value
= vec
->x
>> 6;
4774 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4775 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4776 pt
->y
.value
= vec
->y
>> 6;
4777 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4778 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4782 /***************************************************
4783 * According to the MSDN documentation on WideCharToMultiByte,
4784 * certain codepages cannot set the default_used parameter.
4785 * This returns TRUE if the codepage can set that parameter, false else
4786 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4788 static BOOL
codepage_sets_default_used(UINT codepage
)
4802 * GSUB Table handling functions
4805 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4807 const GSUB_CoverageFormat1
* cf1
;
4811 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4813 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4815 TRACE("Coverage Format 1, %i glyphs\n",count
);
4816 for (i
= 0; i
< count
; i
++)
4817 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4821 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4823 const GSUB_CoverageFormat2
* cf2
;
4826 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4828 count
= GET_BE_WORD(cf2
->RangeCount
);
4829 TRACE("Coverage Format 2, %i ranges\n",count
);
4830 for (i
= 0; i
< count
; i
++)
4832 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4834 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4835 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4837 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4838 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4844 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4849 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4851 const GSUB_ScriptList
*script
;
4852 const GSUB_Script
*deflt
= NULL
;
4854 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4856 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4857 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4859 const GSUB_Script
*scr
;
4862 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4863 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4865 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4867 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4873 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4877 const GSUB_LangSys
*Lang
;
4879 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4881 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4883 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4884 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4886 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4889 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4892 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4898 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4901 const GSUB_FeatureList
*feature
;
4902 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4904 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4905 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4907 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4908 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4910 const GSUB_Feature
*feat
;
4911 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4918 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
4922 const GSUB_LookupList
*lookup
;
4923 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
4925 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
4926 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
4928 const GSUB_LookupTable
*look
;
4929 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
4930 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
4931 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
4932 if (GET_BE_WORD(look
->LookupType
) != 1)
4933 FIXME("We only handle SubType 1\n");
4938 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
4940 const GSUB_SingleSubstFormat1
*ssf1
;
4941 offset
= GET_BE_WORD(look
->SubTable
[j
]);
4942 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
4943 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
4945 int offset
= GET_BE_WORD(ssf1
->Coverage
);
4946 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
4947 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
4949 TRACE(" Glyph 0x%x ->",glyph
);
4950 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
4951 TRACE(" 0x%x\n",glyph
);
4956 const GSUB_SingleSubstFormat2
*ssf2
;
4960 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
4961 offset
= GET_BE_WORD(ssf1
->Coverage
);
4962 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
4963 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
4964 TRACE(" Coverage index %i\n",index
);
4967 TRACE(" Glyph is 0x%x ->",glyph
);
4968 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
4969 TRACE("0x%x\n",glyph
);
4978 static const char* get_opentype_script(const GdiFont
*font
)
4981 * I am not sure if this is the correct way to generate our script tag
4984 switch (font
->charset
)
4986 case ANSI_CHARSET
: return "latn";
4987 case BALTIC_CHARSET
: return "latn"; /* ?? */
4988 case CHINESEBIG5_CHARSET
: return "hani";
4989 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4990 case GB2312_CHARSET
: return "hani";
4991 case GREEK_CHARSET
: return "grek";
4992 case HANGUL_CHARSET
: return "hang";
4993 case RUSSIAN_CHARSET
: return "cyrl";
4994 case SHIFTJIS_CHARSET
: return "kana";
4995 case TURKISH_CHARSET
: return "latn"; /* ?? */
4996 case VIETNAMESE_CHARSET
: return "latn";
4997 case JOHAB_CHARSET
: return "latn"; /* ?? */
4998 case ARABIC_CHARSET
: return "arab";
4999 case HEBREW_CHARSET
: return "hebr";
5000 case THAI_CHARSET
: return "thai";
5001 default: return "latn";
5005 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5007 const GSUB_Header
*header
;
5008 const GSUB_Script
*script
;
5009 const GSUB_LangSys
*language
;
5010 const GSUB_Feature
*feature
;
5012 if (!font
->GSUB_Table
)
5015 header
= font
->GSUB_Table
;
5017 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5020 TRACE("Script not found\n");
5023 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5026 TRACE("Language not found\n");
5029 feature
= GSUB_get_feature(header
, language
, "vrt2");
5031 feature
= GSUB_get_feature(header
, language
, "vert");
5034 TRACE("vrt2/vert feature not found\n");
5037 return GSUB_apply_feature(header
, feature
, glyph
);
5040 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5044 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5045 WCHAR wc
= (WCHAR
)glyph
;
5047 BOOL
*default_used_pointer
;
5050 default_used_pointer
= NULL
;
5051 default_used
= FALSE
;
5052 if (codepage_sets_default_used(font
->codepage
))
5053 default_used_pointer
= &default_used
;
5054 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5057 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5058 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5062 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5064 if (glyph
< 0x100) glyph
+= 0xf000;
5065 /* there is a number of old pre-Unicode "broken" TTFs, which
5066 do have symbols at U+00XX instead of U+f0XX */
5067 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5068 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5070 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5075 /*************************************************************
5076 * freetype_GetGlyphIndices
5078 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5080 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5083 BOOL got_default
= FALSE
;
5087 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5088 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5091 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5093 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5098 EnterCriticalSection( &freetype_cs
);
5100 for(i
= 0; i
< count
; i
++)
5102 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5107 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5109 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5110 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5115 get_text_metrics(physdev
->font
, &textm
);
5116 default_char
= textm
.tmDefaultChar
;
5120 pgi
[i
] = default_char
;
5123 LeaveCriticalSection( &freetype_cs
);
5127 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5129 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5130 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5133 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5135 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5136 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5139 static inline BYTE
get_max_level( UINT format
)
5143 case GGO_GRAY2_BITMAP
: return 4;
5144 case GGO_GRAY4_BITMAP
: return 16;
5145 case GGO_GRAY8_BITMAP
: return 64;
5150 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5152 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5153 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5156 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5157 FT_Face ft_face
= incoming_font
->ft_face
;
5158 GdiFont
*font
= incoming_font
;
5159 FT_UInt glyph_index
;
5160 DWORD width
, height
, pitch
, needed
= 0;
5161 FT_Bitmap ft_bitmap
;
5163 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5165 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5166 double widthRatio
= 1.0;
5167 FT_Matrix transMat
= identityMat
;
5168 FT_Matrix transMatUnrotated
;
5169 BOOL needsTransform
= FALSE
;
5170 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5171 UINT original_index
;
5173 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5174 buflen
, buf
, lpmat
);
5176 TRACE("font transform %f %f %f %f\n",
5177 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5178 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5180 if(format
& GGO_GLYPH_INDEX
) {
5181 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5182 original_index
= glyph
;
5183 format
&= ~GGO_GLYPH_INDEX
;
5185 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5186 ft_face
= font
->ft_face
;
5187 original_index
= glyph_index
;
5190 if(format
& GGO_UNHINTED
) {
5191 load_flags
|= FT_LOAD_NO_HINTING
;
5192 format
&= ~GGO_UNHINTED
;
5195 /* tategaki never appears to happen to lower glyph index */
5196 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5199 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5200 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5201 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5202 font
->gmsize
* sizeof(GM
*));
5204 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5205 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5207 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5208 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5209 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5210 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5211 return 1; /* FIXME */
5215 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5216 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5218 /* Scaling factor */
5223 get_text_metrics(font
, &tm
);
5225 widthRatio
= (double)font
->aveWidth
;
5226 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5229 widthRatio
= font
->scale_y
;
5231 /* Scaling transform */
5232 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5235 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5238 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5240 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5241 needsTransform
= TRUE
;
5244 /* Slant transform */
5245 if (font
->fake_italic
) {
5248 slantMat
.xx
= (1 << 16);
5249 slantMat
.xy
= ((1 << 16) >> 2);
5251 slantMat
.yy
= (1 << 16);
5252 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5253 needsTransform
= TRUE
;
5256 /* Rotation transform */
5257 transMatUnrotated
= transMat
;
5258 if(font
->orientation
&& !tategaki
) {
5259 FT_Matrix rotationMat
;
5261 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5262 pFT_Vector_Unit(&vecAngle
, angle
);
5263 rotationMat
.xx
= vecAngle
.x
;
5264 rotationMat
.xy
= -vecAngle
.y
;
5265 rotationMat
.yx
= -rotationMat
.xy
;
5266 rotationMat
.yy
= rotationMat
.xx
;
5268 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5269 needsTransform
= TRUE
;
5272 /* World transform */
5273 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5276 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5277 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5278 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5279 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5280 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5281 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5282 needsTransform
= TRUE
;
5285 /* Extra transformation specified by caller */
5286 if (!is_identity_MAT2(lpmat
))
5289 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5290 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5291 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5292 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5293 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5294 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5295 needsTransform
= TRUE
;
5298 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5299 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5300 format
== GGO_GRAY8_BITMAP
))
5302 load_flags
|= FT_LOAD_NO_BITMAP
;
5305 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5308 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5312 if(!needsTransform
) {
5313 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5314 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5315 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5317 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5318 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5319 ft_face
->glyph
->metrics
.height
) & -64;
5320 lpgm
->gmCellIncX
= adv
;
5321 lpgm
->gmCellIncY
= 0;
5328 for(xc
= 0; xc
< 2; xc
++) {
5329 for(yc
= 0; yc
< 2; yc
++) {
5330 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5331 xc
* ft_face
->glyph
->metrics
.width
);
5332 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5333 yc
* ft_face
->glyph
->metrics
.height
;
5334 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5335 pFT_Vector_Transform(&vec
, &transMat
);
5336 if(xc
== 0 && yc
== 0) {
5337 left
= right
= vec
.x
;
5338 top
= bottom
= vec
.y
;
5340 if(vec
.x
< left
) left
= vec
.x
;
5341 else if(vec
.x
> right
) right
= vec
.x
;
5342 if(vec
.y
< bottom
) bottom
= vec
.y
;
5343 else if(vec
.y
> top
) top
= vec
.y
;
5348 right
= (right
+ 63) & -64;
5349 bottom
= bottom
& -64;
5350 top
= (top
+ 63) & -64;
5352 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5353 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5355 pFT_Vector_Transform(&vec
, &transMat
);
5356 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5357 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5359 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5361 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5362 adv
= (vec
.x
+63) >> 6;
5366 bbx
= (right
- left
) >> 6;
5367 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5368 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5369 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5370 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5372 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5373 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5374 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5376 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5377 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5379 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5380 FONT_GM(font
,original_index
)->adv
= adv
;
5381 FONT_GM(font
,original_index
)->lsb
= lsb
;
5382 FONT_GM(font
,original_index
)->bbx
= bbx
;
5383 FONT_GM(font
,original_index
)->init
= TRUE
;
5386 if(format
== GGO_METRICS
)
5388 return 1; /* FIXME */
5391 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5392 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5394 TRACE("loaded a bitmap\n");
5400 width
= lpgm
->gmBlackBoxX
;
5401 height
= lpgm
->gmBlackBoxY
;
5402 pitch
= ((width
+ 31) >> 5) << 2;
5403 needed
= pitch
* height
;
5405 if(!buf
|| !buflen
) break;
5407 switch(ft_face
->glyph
->format
) {
5408 case ft_glyph_format_bitmap
:
5410 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5411 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5412 INT h
= ft_face
->glyph
->bitmap
.rows
;
5414 memcpy(dst
, src
, w
);
5415 src
+= ft_face
->glyph
->bitmap
.pitch
;
5421 case ft_glyph_format_outline
:
5422 ft_bitmap
.width
= width
;
5423 ft_bitmap
.rows
= height
;
5424 ft_bitmap
.pitch
= pitch
;
5425 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5426 ft_bitmap
.buffer
= buf
;
5429 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5431 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5433 /* Note: FreeType will only set 'black' bits for us. */
5434 memset(buf
, 0, needed
);
5435 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5439 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5444 case GGO_GRAY2_BITMAP
:
5445 case GGO_GRAY4_BITMAP
:
5446 case GGO_GRAY8_BITMAP
:
5447 case WINE_GGO_GRAY16_BITMAP
:
5449 unsigned int max_level
, row
, col
;
5452 width
= lpgm
->gmBlackBoxX
;
5453 height
= lpgm
->gmBlackBoxY
;
5454 pitch
= (width
+ 3) / 4 * 4;
5455 needed
= pitch
* height
;
5457 if(!buf
|| !buflen
) break;
5459 max_level
= get_max_level( format
);
5461 switch(ft_face
->glyph
->format
) {
5462 case ft_glyph_format_bitmap
:
5464 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5465 INT h
= ft_face
->glyph
->bitmap
.rows
;
5467 memset( buf
, 0, needed
);
5469 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5470 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5471 src
+= ft_face
->glyph
->bitmap
.pitch
;
5476 case ft_glyph_format_outline
:
5478 ft_bitmap
.width
= width
;
5479 ft_bitmap
.rows
= height
;
5480 ft_bitmap
.pitch
= pitch
;
5481 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5482 ft_bitmap
.buffer
= buf
;
5485 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5487 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5489 memset(ft_bitmap
.buffer
, 0, buflen
);
5491 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5493 if (max_level
!= 255)
5495 for (row
= 0, start
= buf
; row
< height
; row
++)
5497 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5498 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5506 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5512 case WINE_GGO_HRGB_BITMAP
:
5513 case WINE_GGO_HBGR_BITMAP
:
5514 case WINE_GGO_VRGB_BITMAP
:
5515 case WINE_GGO_VBGR_BITMAP
:
5516 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5518 switch (ft_face
->glyph
->format
)
5520 case FT_GLYPH_FORMAT_BITMAP
:
5525 width
= lpgm
->gmBlackBoxX
;
5526 height
= lpgm
->gmBlackBoxY
;
5528 needed
= pitch
* height
;
5530 if (!buf
|| !buflen
) break;
5532 memset(buf
, 0, buflen
);
5534 src
= ft_face
->glyph
->bitmap
.buffer
;
5535 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5537 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5540 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5542 if ( src
[x
/ 8] & masks
[x
% 8] )
5543 ((unsigned int *)dst
)[x
] = ~0u;
5552 case FT_GLYPH_FORMAT_OUTLINE
:
5556 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5557 INT x_shift
, y_shift
;
5559 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5560 FT_Render_Mode render_mode
=
5561 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5562 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5564 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5566 if ( render_mode
== FT_RENDER_MODE_LCD
)
5568 lpgm
->gmBlackBoxX
+= 2;
5569 lpgm
->gmptGlyphOrigin
.x
-= 1;
5573 lpgm
->gmBlackBoxY
+= 2;
5574 lpgm
->gmptGlyphOrigin
.y
+= 1;
5578 width
= lpgm
->gmBlackBoxX
;
5579 height
= lpgm
->gmBlackBoxY
;
5581 needed
= pitch
* height
;
5583 if (!buf
|| !buflen
) break;
5585 memset(buf
, 0, buflen
);
5587 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5589 if ( needsTransform
)
5590 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5592 if ( pFT_Library_SetLcdFilter
)
5593 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5594 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5596 src
= ft_face
->glyph
->bitmap
.buffer
;
5597 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5598 src_width
= ft_face
->glyph
->bitmap
.width
;
5599 src_height
= ft_face
->glyph
->bitmap
.rows
;
5601 if ( render_mode
== FT_RENDER_MODE_LCD
)
5609 rgb_interval
= src_pitch
;
5614 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5615 if ( x_shift
< 0 ) x_shift
= 0;
5616 if ( x_shift
+ (src_width
/ hmul
) > width
)
5617 x_shift
= width
- (src_width
/ hmul
);
5619 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5620 if ( y_shift
< 0 ) y_shift
= 0;
5621 if ( y_shift
+ (src_height
/ vmul
) > height
)
5622 y_shift
= height
- (src_height
/ vmul
);
5624 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5625 while ( src_height
)
5627 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5631 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5632 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5633 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5634 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5638 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5639 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5640 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5641 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5644 src
+= src_pitch
* vmul
;
5653 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5665 int contour
, point
= 0, first_pt
;
5666 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5667 TTPOLYGONHEADER
*pph
;
5669 DWORD pph_start
, cpfx
, type
;
5671 if(buflen
== 0) buf
= NULL
;
5673 if (needsTransform
&& buf
) {
5674 pFT_Outline_Transform(outline
, &transMat
);
5677 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5679 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5682 pph
->dwType
= TT_POLYGON_TYPE
;
5683 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5685 needed
+= sizeof(*pph
);
5687 while(point
<= outline
->contours
[contour
]) {
5688 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5689 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5690 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5694 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5697 } while(point
<= outline
->contours
[contour
] &&
5698 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5699 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5700 /* At the end of a contour Windows adds the start point, but
5702 if(point
> outline
->contours
[contour
] &&
5703 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5705 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5707 } else if(point
<= outline
->contours
[contour
] &&
5708 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5709 /* add closing pt for bezier */
5711 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5719 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5722 pph
->cb
= needed
- pph_start
;
5728 /* Convert the quadratic Beziers to cubic Beziers.
5729 The parametric eqn for a cubic Bezier is, from PLRM:
5730 r(t) = at^3 + bt^2 + ct + r0
5731 with the control points:
5736 A quadratic Bezier has the form:
5737 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5739 So equating powers of t leads to:
5740 r1 = 2/3 p1 + 1/3 p0
5741 r2 = 2/3 p1 + 1/3 p2
5742 and of course r0 = p0, r3 = p2
5745 int contour
, point
= 0, first_pt
;
5746 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5747 TTPOLYGONHEADER
*pph
;
5749 DWORD pph_start
, cpfx
, type
;
5750 FT_Vector cubic_control
[4];
5751 if(buflen
== 0) buf
= NULL
;
5753 if (needsTransform
&& buf
) {
5754 pFT_Outline_Transform(outline
, &transMat
);
5757 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5759 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5762 pph
->dwType
= TT_POLYGON_TYPE
;
5763 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5765 needed
+= sizeof(*pph
);
5767 while(point
<= outline
->contours
[contour
]) {
5768 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5769 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5770 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5773 if(type
== TT_PRIM_LINE
) {
5775 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5779 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5782 /* FIXME: Possible optimization in endpoint calculation
5783 if there are two consecutive curves */
5784 cubic_control
[0] = outline
->points
[point
-1];
5785 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5786 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5787 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5788 cubic_control
[0].x
>>= 1;
5789 cubic_control
[0].y
>>= 1;
5791 if(point
+1 > outline
->contours
[contour
])
5792 cubic_control
[3] = outline
->points
[first_pt
];
5794 cubic_control
[3] = outline
->points
[point
+1];
5795 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5796 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5797 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5798 cubic_control
[3].x
>>= 1;
5799 cubic_control
[3].y
>>= 1;
5802 /* r1 = 1/3 p0 + 2/3 p1
5803 r2 = 1/3 p2 + 2/3 p1 */
5804 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5805 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5806 cubic_control
[2] = cubic_control
[1];
5807 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5808 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5809 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5810 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5812 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5813 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5814 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5819 } while(point
<= outline
->contours
[contour
] &&
5820 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5821 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5822 /* At the end of a contour Windows adds the start point,
5823 but only for Beziers and we've already done that.
5825 if(point
<= outline
->contours
[contour
] &&
5826 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5827 /* This is the closing pt of a bezier, but we've already
5828 added it, so just inc point and carry on */
5835 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5838 pph
->cb
= needed
- pph_start
;
5844 FIXME("Unsupported format %d\n", format
);
5850 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5852 FT_Face ft_face
= font
->ft_face
;
5853 FT_WinFNT_HeaderRec winfnt_header
;
5854 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5855 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5856 font
->potm
->otmSize
= size
;
5858 #define TM font->potm->otmTextMetrics
5859 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5861 TM
.tmHeight
= winfnt_header
.pixel_height
;
5862 TM
.tmAscent
= winfnt_header
.ascent
;
5863 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5864 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5865 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5866 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5867 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5868 TM
.tmWeight
= winfnt_header
.weight
;
5870 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5871 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5872 TM
.tmFirstChar
= winfnt_header
.first_char
;
5873 TM
.tmLastChar
= winfnt_header
.last_char
;
5874 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5875 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5876 TM
.tmItalic
= winfnt_header
.italic
;
5877 TM
.tmUnderlined
= font
->underline
;
5878 TM
.tmStruckOut
= font
->strikeout
;
5879 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5880 TM
.tmCharSet
= winfnt_header
.charset
;
5884 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5885 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5886 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5887 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5888 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5889 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5890 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
5891 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
5893 TM
.tmDigitizedAspectX
= 96; /* FIXME */
5894 TM
.tmDigitizedAspectY
= 96; /* FIXME */
5896 TM
.tmLastChar
= 255;
5897 TM
.tmDefaultChar
= 32;
5898 TM
.tmBreakChar
= 32;
5899 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
5900 TM
.tmUnderlined
= font
->underline
;
5901 TM
.tmStruckOut
= font
->strikeout
;
5902 /* NB inverted meaning of TMPF_FIXED_PITCH */
5903 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
5904 TM
.tmCharSet
= font
->charset
;
5912 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
5914 double scale_x
, scale_y
;
5918 scale_x
= (double)font
->aveWidth
;
5919 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5922 scale_x
= font
->scale_y
;
5924 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5925 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5927 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5928 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5930 SCALE_Y(ptm
->tmHeight
);
5931 SCALE_Y(ptm
->tmAscent
);
5932 SCALE_Y(ptm
->tmDescent
);
5933 SCALE_Y(ptm
->tmInternalLeading
);
5934 SCALE_Y(ptm
->tmExternalLeading
);
5935 SCALE_Y(ptm
->tmOverhang
);
5937 SCALE_X(ptm
->tmAveCharWidth
);
5938 SCALE_X(ptm
->tmMaxCharWidth
);
5944 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
5946 double scale_x
, scale_y
;
5950 scale_x
= (double)font
->aveWidth
;
5951 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5954 scale_x
= font
->scale_y
;
5956 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
5957 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
5959 scale_font_metrics(font
, &potm
->otmTextMetrics
);
5961 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5962 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5964 SCALE_Y(potm
->otmAscent
);
5965 SCALE_Y(potm
->otmDescent
);
5966 SCALE_Y(potm
->otmLineGap
);
5967 SCALE_Y(potm
->otmsCapEmHeight
);
5968 SCALE_Y(potm
->otmsXHeight
);
5969 SCALE_Y(potm
->otmrcFontBox
.top
);
5970 SCALE_Y(potm
->otmrcFontBox
.bottom
);
5971 SCALE_X(potm
->otmrcFontBox
.left
);
5972 SCALE_X(potm
->otmrcFontBox
.right
);
5973 SCALE_Y(potm
->otmMacAscent
);
5974 SCALE_Y(potm
->otmMacDescent
);
5975 SCALE_Y(potm
->otmMacLineGap
);
5976 SCALE_X(potm
->otmptSubscriptSize
.x
);
5977 SCALE_Y(potm
->otmptSubscriptSize
.y
);
5978 SCALE_X(potm
->otmptSubscriptOffset
.x
);
5979 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
5980 SCALE_X(potm
->otmptSuperscriptSize
.x
);
5981 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
5982 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
5983 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
5984 SCALE_Y(potm
->otmsStrikeoutSize
);
5985 SCALE_Y(potm
->otmsStrikeoutPosition
);
5986 SCALE_Y(potm
->otmsUnderscoreSize
);
5987 SCALE_Y(potm
->otmsUnderscorePosition
);
5993 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
5997 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
5999 /* Make sure that the font has sane width/height ratio */
6002 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6004 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6009 *ptm
= font
->potm
->otmTextMetrics
;
6010 scale_font_metrics(font
, ptm
);
6014 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6018 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6020 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6026 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6029 FT_Face ft_face
= font
->ft_face
;
6030 UINT needed
, lenfam
, lensty
;
6032 TT_HoriHeader
*pHori
;
6033 TT_Postscript
*pPost
;
6034 FT_Fixed x_scale
, y_scale
;
6035 WCHAR
*family_nameW
, *style_nameW
;
6036 static const WCHAR spaceW
[] = {' ', '\0'};
6038 INT ascent
, descent
;
6040 TRACE("font=%p\n", font
);
6042 if(!FT_IS_SCALABLE(ft_face
))
6045 needed
= sizeof(*font
->potm
);
6047 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6048 family_nameW
= strdupW(font
->name
);
6050 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6052 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6053 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6054 style_nameW
, lensty
/sizeof(WCHAR
));
6056 /* These names should be read from the TT name table */
6058 /* length of otmpFamilyName */
6061 /* length of otmpFaceName */
6062 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6063 needed
+= lenfam
; /* just the family name */
6065 needed
+= lenfam
+ lensty
; /* family + " " + style */
6068 /* length of otmpStyleName */
6071 /* length of otmpFullName */
6072 needed
+= lenfam
+ lensty
;
6075 x_scale
= ft_face
->size
->metrics
.x_scale
;
6076 y_scale
= ft_face
->size
->metrics
.y_scale
;
6078 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6080 FIXME("Can't find OS/2 table - not TT font?\n");
6084 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6086 FIXME("Can't find HHEA table - not TT font?\n");
6090 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6092 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",
6093 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6094 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6095 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6096 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6097 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6099 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6100 font
->potm
->otmSize
= needed
;
6102 #define TM font->potm->otmTextMetrics
6104 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6105 ascent
= pHori
->Ascender
;
6106 descent
= -pHori
->Descender
;
6108 ascent
= pOS2
->usWinAscent
;
6109 descent
= pOS2
->usWinDescent
;
6113 TM
.tmAscent
= font
->yMax
;
6114 TM
.tmDescent
= -font
->yMin
;
6115 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6117 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6118 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6119 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6120 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6123 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6126 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6128 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6129 ((ascent
+ descent
) -
6130 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6132 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6133 if (TM
.tmAveCharWidth
== 0) {
6134 TM
.tmAveCharWidth
= 1;
6136 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6137 TM
.tmWeight
= FW_REGULAR
;
6138 if (font
->fake_bold
)
6139 TM
.tmWeight
= FW_BOLD
;
6142 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6144 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6145 TM
.tmWeight
= pOS2
->usWeightClass
;
6147 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6148 TM
.tmWeight
= pOS2
->usWeightClass
;
6151 TM
.tmDigitizedAspectX
= 300;
6152 TM
.tmDigitizedAspectY
= 300;
6153 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6154 * symbol range to 0 - f0ff
6157 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6162 case 1257: /* Baltic */
6163 TM
.tmLastChar
= 0xf8fd;
6166 TM
.tmLastChar
= 0xf0ff;
6168 TM
.tmBreakChar
= 0x20;
6169 TM
.tmDefaultChar
= 0x1f;
6173 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6174 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6176 if(pOS2
->usFirstCharIndex
<= 1)
6177 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6178 else if (pOS2
->usFirstCharIndex
> 0xff)
6179 TM
.tmBreakChar
= 0x20;
6181 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6182 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6184 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6185 TM
.tmUnderlined
= font
->underline
;
6186 TM
.tmStruckOut
= font
->strikeout
;
6188 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6189 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6190 (pOS2
->version
== 0xFFFFU
||
6191 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6192 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6194 TM
.tmPitchAndFamily
= 0;
6196 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6198 case PAN_FAMILY_SCRIPT
:
6199 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6202 case PAN_FAMILY_DECORATIVE
:
6203 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6208 case PAN_FAMILY_TEXT_DISPLAY
:
6209 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6210 /* which is clearly not what the panose spec says. */
6212 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6213 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6214 TM
.tmPitchAndFamily
= FF_MODERN
;
6217 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6222 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6225 case PAN_SERIF_COVE
:
6226 case PAN_SERIF_OBTUSE_COVE
:
6227 case PAN_SERIF_SQUARE_COVE
:
6228 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6229 case PAN_SERIF_SQUARE
:
6230 case PAN_SERIF_THIN
:
6231 case PAN_SERIF_BONE
:
6232 case PAN_SERIF_EXAGGERATED
:
6233 case PAN_SERIF_TRIANGLE
:
6234 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6237 case PAN_SERIF_NORMAL_SANS
:
6238 case PAN_SERIF_OBTUSE_SANS
:
6239 case PAN_SERIF_PERP_SANS
:
6240 case PAN_SERIF_FLARED
:
6241 case PAN_SERIF_ROUNDED
:
6242 TM
.tmPitchAndFamily
|= FF_SWISS
;
6249 if(FT_IS_SCALABLE(ft_face
))
6250 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6252 if(FT_IS_SFNT(ft_face
))
6254 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6255 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6257 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6260 TM
.tmCharSet
= font
->charset
;
6262 font
->potm
->otmFiller
= 0;
6263 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6264 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6265 font
->potm
->otmfsType
= pOS2
->fsType
;
6266 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6267 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6268 font
->potm
->otmItalicAngle
= 0; /* POST table */
6269 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6270 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6271 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6272 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6273 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6274 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6275 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6276 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6277 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6278 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6279 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6280 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6281 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6282 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6283 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6284 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6285 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6286 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6287 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6288 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6289 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6290 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6291 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6292 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6294 font
->potm
->otmsUnderscoreSize
= 0;
6295 font
->potm
->otmsUnderscorePosition
= 0;
6297 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6298 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6302 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6303 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6304 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6305 strcpyW((WCHAR
*)cp
, family_nameW
);
6307 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6308 strcpyW((WCHAR
*)cp
, style_nameW
);
6310 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6311 strcpyW((WCHAR
*)cp
, family_nameW
);
6312 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6313 strcatW((WCHAR
*)cp
, spaceW
);
6314 strcatW((WCHAR
*)cp
, style_nameW
);
6315 cp
+= lenfam
+ lensty
;
6318 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6319 strcpyW((WCHAR
*)cp
, family_nameW
);
6320 strcatW((WCHAR
*)cp
, spaceW
);
6321 strcatW((WCHAR
*)cp
, style_nameW
);
6325 HeapFree(GetProcessHeap(), 0, style_nameW
);
6326 HeapFree(GetProcessHeap(), 0, family_nameW
);
6330 /*************************************************************
6331 * freetype_GetGlyphOutline
6333 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6334 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6336 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6341 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6342 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6346 EnterCriticalSection( &freetype_cs
);
6347 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6348 LeaveCriticalSection( &freetype_cs
);
6352 /*************************************************************
6353 * freetype_GetTextMetrics
6355 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6357 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6362 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6363 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6367 EnterCriticalSection( &freetype_cs
);
6368 ret
= get_text_metrics( physdev
->font
, metrics
);
6369 LeaveCriticalSection( &freetype_cs
);
6373 /*************************************************************
6374 * freetype_GetOutlineTextMetrics
6376 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6378 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6383 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6384 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6387 TRACE("font=%p\n", physdev
->font
);
6389 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6392 EnterCriticalSection( &freetype_cs
);
6394 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6396 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6398 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6399 scale_outline_font_metrics(physdev
->font
, potm
);
6401 ret
= physdev
->font
->potm
->otmSize
;
6403 LeaveCriticalSection( &freetype_cs
);
6407 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6409 HFONTLIST
*hfontlist
;
6410 child
->font
= alloc_font();
6411 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6412 if(!child
->font
->ft_face
)
6414 free_font(child
->font
);
6419 child
->font
->font_desc
= font
->font_desc
;
6420 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6421 child
->font
->orientation
= font
->orientation
;
6422 child
->font
->scale_y
= font
->scale_y
;
6423 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6424 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6425 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6426 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6427 child
->font
->base_font
= font
;
6428 list_add_head(&child_font_list
, &child
->font
->entry
);
6429 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6433 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6436 CHILD_FONT
*child_font
;
6439 font
= font
->base_font
;
6441 *linked_font
= font
;
6443 if((*glyph
= get_glyph_index(font
, c
)))
6445 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6449 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6451 if(!child_font
->font
)
6452 if(!load_child_font(font
, child_font
))
6455 if(!child_font
->font
->ft_face
)
6457 g
= get_glyph_index(child_font
->font
, c
);
6458 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6462 *linked_font
= child_font
->font
;
6469 /*************************************************************
6470 * freetype_GetCharWidth
6472 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6474 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6477 FT_UInt glyph_index
;
6478 GdiFont
*linked_font
;
6479 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6483 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6484 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6487 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6490 EnterCriticalSection( &freetype_cs
);
6491 for(c
= firstChar
; c
<= lastChar
; c
++) {
6492 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6493 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6494 &gm
, 0, NULL
, &identity
);
6495 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6497 LeaveCriticalSection( &freetype_cs
);
6501 /*************************************************************
6502 * freetype_GetCharABCWidths
6504 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6506 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6509 FT_UInt glyph_index
;
6510 GdiFont
*linked_font
;
6511 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6515 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6516 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6519 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6522 EnterCriticalSection( &freetype_cs
);
6524 for(c
= firstChar
; c
<= lastChar
; c
++) {
6525 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6526 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6527 &gm
, 0, NULL
, &identity
);
6528 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6529 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6530 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6531 FONT_GM(linked_font
,glyph_index
)->bbx
;
6533 LeaveCriticalSection( &freetype_cs
);
6537 /*************************************************************
6538 * freetype_GetCharABCWidthsI
6540 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6542 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6545 FT_UInt glyph_index
;
6546 GdiFont
*linked_font
;
6547 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6551 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6552 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6555 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6559 EnterCriticalSection( &freetype_cs
);
6561 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6563 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6564 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6565 &gm
, 0, NULL
, &identity
);
6566 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6567 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6568 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6569 - FONT_GM(linked_font
,c
)->bbx
;
6572 for(c
= 0; c
< count
; c
++) {
6573 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6574 &gm
, 0, NULL
, &identity
);
6575 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6576 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6577 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6578 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6581 LeaveCriticalSection( &freetype_cs
);
6585 /*************************************************************
6586 * freetype_GetTextExtentExPoint
6588 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6589 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6591 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6596 FT_UInt glyph_index
;
6597 GdiFont
*linked_font
;
6598 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6602 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6603 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6606 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6609 EnterCriticalSection( &freetype_cs
);
6612 get_text_metrics( physdev
->font
, &tm
);
6613 size
->cy
= tm
.tmHeight
;
6615 for(idx
= 0; idx
< count
; idx
++) {
6616 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6617 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6618 &gm
, 0, NULL
, &identity
);
6619 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6621 if (! pnfit
|| ext
<= max_ext
) {
6631 LeaveCriticalSection( &freetype_cs
);
6632 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6636 /*************************************************************
6637 * freetype_GetTextExtentExPointI
6639 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6640 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6642 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6647 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6651 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6652 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6655 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6658 EnterCriticalSection( &freetype_cs
);
6661 get_text_metrics(physdev
->font
, &tm
);
6662 size
->cy
= tm
.tmHeight
;
6664 for(idx
= 0; idx
< count
; idx
++) {
6665 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6666 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6668 if (! pnfit
|| ext
<= max_ext
) {
6678 LeaveCriticalSection( &freetype_cs
);
6679 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6683 /*************************************************************
6684 * freetype_GetFontData
6686 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6688 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6692 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6693 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6696 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6697 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6698 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6700 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6703 /*************************************************************
6704 * freetype_GetTextFace
6706 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6709 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6713 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6714 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6717 n
= strlenW(physdev
->font
->name
) + 1;
6720 lstrcpynW(str
, physdev
->font
->name
, count
);
6726 /*************************************************************
6727 * freetype_GetTextCharsetInfo
6729 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6731 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6735 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6736 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6738 if (fs
) *fs
= physdev
->font
->fs
;
6739 return physdev
->font
->charset
;
6742 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6744 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6745 struct list
*first_hfont
;
6749 EnterCriticalSection( &freetype_cs
);
6750 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6751 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6752 if(font
== linked_font
)
6753 *new_hfont
= dc
->hFont
;
6756 first_hfont
= list_head(&linked_font
->hfontlist
);
6757 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6759 LeaveCriticalSection( &freetype_cs
);
6763 /* Retrieve a list of supported Unicode ranges for a given font.
6764 * Can be called with NULL gs to calculate the buffer size. Returns
6765 * the number of ranges found.
6767 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6769 DWORD num_ranges
= 0;
6771 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6774 FT_ULong char_code
, char_code_prev
;
6777 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6779 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6780 face
->num_glyphs
, glyph_code
, char_code
);
6782 if (!glyph_code
) return 0;
6786 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6787 gs
->ranges
[0].cGlyphs
= 0;
6788 gs
->cGlyphsSupported
= 0;
6794 if (char_code
< char_code_prev
)
6796 ERR("expected increasing char code from FT_Get_Next_Char\n");
6799 if (char_code
- char_code_prev
> 1)
6804 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6805 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6806 gs
->cGlyphsSupported
++;
6811 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6812 gs
->cGlyphsSupported
++;
6814 char_code_prev
= char_code
;
6815 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6819 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6824 /*************************************************************
6825 * freetype_GetFontUnicodeRanges
6827 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6829 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6830 DWORD size
, num_ranges
;
6834 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6835 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6838 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6839 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6842 glyphset
->cbThis
= size
;
6843 glyphset
->cRanges
= num_ranges
;
6844 glyphset
->flAccel
= 0;
6849 /*************************************************************
6850 * freetype_FontIsLinked
6852 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6854 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6859 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6860 return dev
->funcs
->pFontIsLinked( dev
);
6864 EnterCriticalSection( &freetype_cs
);
6865 ret
= !list_empty(&physdev
->font
->child_fonts
);
6866 LeaveCriticalSection( &freetype_cs
);
6870 static BOOL
is_hinting_enabled(void)
6872 /* Use the >= 2.2.0 function if available */
6873 if(pFT_Get_TrueType_Engine_Type
)
6875 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6876 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6878 #ifdef FT_DRIVER_HAS_HINTER
6883 /* otherwise if we've been compiled with < 2.2.0 headers
6884 use the internal macro */
6885 mod
= pFT_Get_Module(library
, "truetype");
6886 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
6894 static BOOL
is_subpixel_rendering_enabled( void )
6896 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6897 return pFT_Library_SetLcdFilter
&&
6898 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
6904 /*************************************************************************
6905 * GetRasterizerCaps (GDI32.@)
6907 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
6909 static int hinting
= -1;
6910 static int subpixel
= -1;
6914 hinting
= is_hinting_enabled();
6915 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
6918 if ( subpixel
== -1 )
6920 subpixel
= is_subpixel_rendering_enabled();
6921 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
6924 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
6925 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
6927 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
6928 lprs
->nLanguageID
= 0;
6932 /*************************************************************
6933 * freetype_GdiRealizationInfo
6935 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
6937 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6938 realization_info_t
*info
= ptr
;
6942 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
6943 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
6946 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
6949 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
6952 info
->cache_num
= physdev
->font
->cache_num
;
6953 info
->unknown2
= -1;
6957 /*************************************************************************
6958 * Kerning support for TrueType fonts
6960 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6962 struct TT_kern_table
6968 struct TT_kern_subtable
6977 USHORT horizontal
: 1;
6979 USHORT cross_stream
: 1;
6980 USHORT override
: 1;
6981 USHORT reserved1
: 4;
6987 struct TT_format0_kern_subtable
6991 USHORT entrySelector
;
7002 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7003 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7004 const USHORT
*glyph_to_char
,
7005 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7008 const struct TT_kern_pair
*tt_kern_pair
;
7010 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7012 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7014 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7015 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7016 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7018 if (!kern_pair
|| !cPairs
)
7021 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7023 nPairs
= min(nPairs
, cPairs
);
7025 for (i
= 0; i
< nPairs
; i
++)
7027 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7028 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7029 /* this algorithm appears to better match what Windows does */
7030 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7031 if (kern_pair
->iKernAmount
< 0)
7033 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7034 kern_pair
->iKernAmount
-= font
->ppem
;
7036 else if (kern_pair
->iKernAmount
> 0)
7038 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7039 kern_pair
->iKernAmount
+= font
->ppem
;
7041 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7043 TRACE("left %u right %u value %d\n",
7044 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7048 TRACE("copied %u entries\n", nPairs
);
7052 /*************************************************************
7053 * freetype_GetKerningPairs
7055 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7059 const struct TT_kern_table
*tt_kern_table
;
7060 const struct TT_kern_subtable
*tt_kern_subtable
;
7062 USHORT
*glyph_to_char
;
7064 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7066 if (!(font
= physdev
->font
))
7068 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7069 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7073 EnterCriticalSection( &freetype_cs
);
7074 if (font
->total_kern_pairs
!= (DWORD
)-1)
7076 if (cPairs
&& kern_pair
)
7078 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7079 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7081 else cPairs
= font
->total_kern_pairs
;
7083 LeaveCriticalSection( &freetype_cs
);
7087 font
->total_kern_pairs
= 0;
7089 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7091 if (length
== GDI_ERROR
)
7093 TRACE("no kerning data in the font\n");
7094 LeaveCriticalSection( &freetype_cs
);
7098 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7101 WARN("Out of memory\n");
7102 LeaveCriticalSection( &freetype_cs
);
7106 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7108 /* build a glyph index to char code map */
7109 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7112 WARN("Out of memory allocating a glyph index to char code map\n");
7113 HeapFree(GetProcessHeap(), 0, buf
);
7114 LeaveCriticalSection( &freetype_cs
);
7118 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7124 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7126 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7127 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7131 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7133 /* FIXME: This doesn't match what Windows does: it does some fancy
7134 * things with duplicate glyph index to char code mappings, while
7135 * we just avoid overriding existing entries.
7137 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7138 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7140 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7147 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7148 for (n
= 0; n
<= 65535; n
++)
7149 glyph_to_char
[n
] = (USHORT
)n
;
7152 tt_kern_table
= buf
;
7153 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7154 TRACE("version %u, nTables %u\n",
7155 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7157 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7159 for (i
= 0; i
< nTables
; i
++)
7161 struct TT_kern_subtable tt_kern_subtable_copy
;
7163 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7164 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7165 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7167 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7168 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7169 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7171 /* According to the TrueType specification this is the only format
7172 * that will be properly interpreted by Windows and OS/2
7174 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7176 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7178 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7179 glyph_to_char
, NULL
, 0);
7180 font
->total_kern_pairs
+= new_chunk
;
7182 if (!font
->kern_pairs
)
7183 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7184 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7186 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7187 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7189 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7190 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7193 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7195 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7198 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7199 HeapFree(GetProcessHeap(), 0, buf
);
7201 if (cPairs
&& kern_pair
)
7203 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7204 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7206 else cPairs
= font
->total_kern_pairs
;
7208 LeaveCriticalSection( &freetype_cs
);
7212 static const struct gdi_dc_funcs freetype_funcs
=
7214 NULL
, /* pAbortDoc */
7215 NULL
, /* pAbortPath */
7216 NULL
, /* pAlphaBlend */
7217 NULL
, /* pAngleArc */
7220 NULL
, /* pBeginPath */
7221 NULL
, /* pBlendImage */
7222 NULL
, /* pChoosePixelFormat */
7224 NULL
, /* pCloseFigure */
7225 NULL
, /* pCopyBitmap */
7226 NULL
, /* pCreateBitmap */
7227 NULL
, /* pCreateCompatibleDC */
7228 freetype_CreateDC
, /* pCreateDC */
7229 NULL
, /* pDeleteBitmap */
7230 freetype_DeleteDC
, /* pDeleteDC */
7231 NULL
, /* pDeleteObject */
7232 NULL
, /* pDescribePixelFormat */
7233 NULL
, /* pDeviceCapabilities */
7234 NULL
, /* pEllipse */
7236 NULL
, /* pEndPage */
7237 NULL
, /* pEndPath */
7238 freetype_EnumFonts
, /* pEnumFonts */
7239 NULL
, /* pEnumICMProfiles */
7240 NULL
, /* pExcludeClipRect */
7241 NULL
, /* pExtDeviceMode */
7242 NULL
, /* pExtEscape */
7243 NULL
, /* pExtFloodFill */
7244 NULL
, /* pExtSelectClipRgn */
7245 NULL
, /* pExtTextOut */
7246 NULL
, /* pFillPath */
7247 NULL
, /* pFillRgn */
7248 NULL
, /* pFlattenPath */
7249 freetype_FontIsLinked
, /* pFontIsLinked */
7250 NULL
, /* pFrameRgn */
7251 NULL
, /* pGdiComment */
7252 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7253 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7254 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7255 freetype_GetCharWidth
, /* pGetCharWidth */
7256 NULL
, /* pGetDeviceCaps */
7257 NULL
, /* pGetDeviceGammaRamp */
7258 freetype_GetFontData
, /* pGetFontData */
7259 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7260 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7261 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7262 NULL
, /* pGetICMProfile */
7263 NULL
, /* pGetImage */
7264 freetype_GetKerningPairs
, /* pGetKerningPairs */
7265 NULL
, /* pGetNearestColor */
7266 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7267 NULL
, /* pGetPixel */
7268 NULL
, /* pGetPixelFormat */
7269 NULL
, /* pGetSystemPaletteEntries */
7270 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7271 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7272 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7273 freetype_GetTextFace
, /* pGetTextFace */
7274 freetype_GetTextMetrics
, /* pGetTextMetrics */
7275 NULL
, /* pGradientFill */
7276 NULL
, /* pIntersectClipRect */
7277 NULL
, /* pInvertRgn */
7279 NULL
, /* pModifyWorldTransform */
7281 NULL
, /* pOffsetClipRgn */
7282 NULL
, /* pOffsetViewportOrg */
7283 NULL
, /* pOffsetWindowOrg */
7284 NULL
, /* pPaintRgn */
7287 NULL
, /* pPolyBezier */
7288 NULL
, /* pPolyBezierTo */
7289 NULL
, /* pPolyDraw */
7290 NULL
, /* pPolyPolygon */
7291 NULL
, /* pPolyPolyline */
7292 NULL
, /* pPolygon */
7293 NULL
, /* pPolyline */
7294 NULL
, /* pPolylineTo */
7295 NULL
, /* pPutImage */
7296 NULL
, /* pRealizeDefaultPalette */
7297 NULL
, /* pRealizePalette */
7298 NULL
, /* pRectangle */
7299 NULL
, /* pResetDC */
7300 NULL
, /* pRestoreDC */
7301 NULL
, /* pRoundRect */
7303 NULL
, /* pScaleViewportExt */
7304 NULL
, /* pScaleWindowExt */
7305 NULL
, /* pSelectBitmap */
7306 NULL
, /* pSelectBrush */
7307 NULL
, /* pSelectClipPath */
7308 freetype_SelectFont
, /* pSelectFont */
7309 NULL
, /* pSelectPalette */
7310 NULL
, /* pSelectPen */
7311 NULL
, /* pSetArcDirection */
7312 NULL
, /* pSetBkColor */
7313 NULL
, /* pSetBkMode */
7314 NULL
, /* pSetDCBrushColor */
7315 NULL
, /* pSetDCPenColor */
7316 NULL
, /* pSetDIBColorTable */
7317 NULL
, /* pSetDIBitsToDevice */
7318 NULL
, /* pSetDeviceClipping */
7319 NULL
, /* pSetDeviceGammaRamp */
7320 NULL
, /* pSetLayout */
7321 NULL
, /* pSetMapMode */
7322 NULL
, /* pSetMapperFlags */
7323 NULL
, /* pSetPixel */
7324 NULL
, /* pSetPixelFormat */
7325 NULL
, /* pSetPolyFillMode */
7326 NULL
, /* pSetROP2 */
7327 NULL
, /* pSetRelAbs */
7328 NULL
, /* pSetStretchBltMode */
7329 NULL
, /* pSetTextAlign */
7330 NULL
, /* pSetTextCharacterExtra */
7331 NULL
, /* pSetTextColor */
7332 NULL
, /* pSetTextJustification */
7333 NULL
, /* pSetViewportExt */
7334 NULL
, /* pSetViewportOrg */
7335 NULL
, /* pSetWindowExt */
7336 NULL
, /* pSetWindowOrg */
7337 NULL
, /* pSetWorldTransform */
7338 NULL
, /* pStartDoc */
7339 NULL
, /* pStartPage */
7340 NULL
, /* pStretchBlt */
7341 NULL
, /* pStretchDIBits */
7342 NULL
, /* pStrokeAndFillPath */
7343 NULL
, /* pStrokePath */
7344 NULL
, /* pSwapBuffers */
7345 NULL
, /* pUnrealizePalette */
7346 NULL
, /* pWidenPath */
7347 /* OpenGL not supported */
7350 #else /* HAVE_FREETYPE */
7352 /*************************************************************************/
7354 BOOL
WineEngInit(void)
7358 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7363 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7365 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7369 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7371 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7375 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7377 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7381 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7386 /*************************************************************************
7387 * GetRasterizerCaps (GDI32.@)
7389 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7391 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7393 lprs
->nLanguageID
= 0;
7397 #endif /* HAVE_FREETYPE */