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 void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
1994 SYSTEM_LINKS
*font_link
;
1995 BOOL existing
= FALSE
;
1997 memset(&fs
, 0, sizeof(fs
));
1998 psub
= get_font_subst(&font_subst_list
, name
, -1);
1999 /* Don't store fonts that are only substitutes for other fonts */
2002 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2006 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2008 if(!strcmpiW(font_link
->font_name
, name
))
2017 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2018 font_link
->font_name
= strdupW(name
);
2019 list_init(&font_link
->links
);
2022 for (i
= 0; values
[i
] != NULL
; i
++)
2024 CHILD_FONT
*child_font
;
2027 if (!strcmpiW(name
,value
))
2029 psub
= get_font_subst(&font_subst_list
, value
, -1);
2031 value
= psub
->to
.name
;
2032 family
= find_family_from_name(value
);
2036 /* Use first extant filename for this Family */
2037 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2041 file
= strrchr(face
->file
, '/');
2050 fileW
= towstr(CP_UNIXCP
, file
);
2052 face
= find_face_from_filename(fileW
, value
);
2055 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2059 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2060 child_font
->face
= face
;
2061 child_font
->font
= NULL
;
2062 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2063 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2064 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2065 list_add_tail(&font_link
->links
, &child_font
->entry
);
2067 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2068 HeapFree(GetProcessHeap(), 0, fileW
);
2071 family
= find_family_from_name(font_link
->font_name
);
2074 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2076 face
->fs_links
= fs
;
2080 list_add_tail(&system_links
, &font_link
->entry
);
2085 /*************************************************************
2088 static BOOL
init_system_links(void)
2092 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2093 WCHAR
*value
, *data
;
2094 WCHAR
*entry
, *next
;
2095 SYSTEM_LINKS
*font_link
, *system_font_link
;
2096 CHILD_FONT
*child_font
;
2097 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2098 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2099 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2106 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2108 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2109 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2110 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2111 val_len
= max_val
+ 1;
2112 data_len
= max_data
;
2114 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2116 memset(&fs
, 0, sizeof(fs
));
2117 psub
= get_font_subst(&font_subst_list
, value
, -1);
2118 /* Don't store fonts that are only substitutes for other fonts */
2121 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2124 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2125 font_link
->font_name
= strdupW(value
);
2126 list_init(&font_link
->links
);
2127 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2130 CHILD_FONT
*child_font
;
2132 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2134 next
= entry
+ strlenW(entry
) + 1;
2136 face_name
= strchrW(entry
, ',');
2140 while(isspaceW(*face_name
))
2143 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2145 face_name
= psub
->to
.name
;
2147 face
= find_face_from_filename(entry
, face_name
);
2150 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2154 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2155 child_font
->face
= face
;
2156 child_font
->font
= NULL
;
2157 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2158 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2159 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2160 list_add_tail(&font_link
->links
, &child_font
->entry
);
2162 family
= find_family_from_name(font_link
->font_name
);
2165 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2167 face
->fs_links
= fs
;
2170 list_add_tail(&system_links
, &font_link
->entry
);
2172 val_len
= max_val
+ 1;
2173 data_len
= max_data
;
2176 HeapFree(GetProcessHeap(), 0, value
);
2177 HeapFree(GetProcessHeap(), 0, data
);
2182 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2184 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2188 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2190 const FontSubst
*psub2
;
2191 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2193 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2195 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2196 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2198 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2199 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2201 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2203 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2209 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2212 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2213 system_font_link
->font_name
= strdupW(System
);
2214 list_init(&system_font_link
->links
);
2215 memset(&fs
, 0, sizeof(fs
));
2217 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2220 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2221 child_font
->face
= face
;
2222 child_font
->font
= NULL
;
2223 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2224 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2225 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2226 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2228 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2230 if(!strcmpiW(font_link
->font_name
, Tahoma
))
2232 CHILD_FONT
*font_link_entry
;
2233 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2235 CHILD_FONT
*new_child
;
2236 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2237 new_child
->face
= font_link_entry
->face
;
2238 new_child
->font
= NULL
;
2239 fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2240 fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2241 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 #ifdef SONAME_LIBFONTCONFIG
2300 static void load_fontconfig_fonts(void)
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
);
2370 #elif defined(HAVE_CARBON_CARBON_H)
2372 static void load_mac_font_callback(const void *value
, void *context
)
2374 CFStringRef pathStr
= value
;
2378 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2379 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2380 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2382 TRACE("font file %s\n", path
);
2383 AddFontFileToList(path
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2385 HeapFree(GetProcessHeap(), 0, path
);
2388 static void load_mac_fonts(void)
2390 CFStringRef removeDupesKey
;
2391 CFBooleanRef removeDupesValue
;
2392 CFDictionaryRef options
;
2393 CTFontCollectionRef col
;
2395 CFMutableSetRef paths
;
2398 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2399 removeDupesValue
= kCFBooleanTrue
;
2400 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2401 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2402 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2403 if (options
) CFRelease(options
);
2406 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2410 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2414 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2418 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2421 WARN("CFSetCreateMutable failed\n");
2426 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2428 CTFontDescriptorRef desc
;
2437 desc
= CFArrayGetValueAtIndex(descs
, i
);
2439 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2440 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2441 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2442 if (!font
) continue;
2444 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2451 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2453 if (status
!= noErr
) continue;
2455 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2458 ext
= CFURLCopyPathExtension(url
);
2461 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2462 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2471 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2473 if (!path
) continue;
2475 CFSetAddValue(paths
, path
);
2481 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2487 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2490 const char *data_dir
= wine_get_data_dir();
2492 if (!data_dir
) data_dir
= wine_get_build_dir();
2499 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2501 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2503 strcpy(unix_name
, data_dir
);
2504 strcat(unix_name
, "/fonts/");
2506 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2508 EnterCriticalSection( &freetype_cs
);
2509 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2510 LeaveCriticalSection( &freetype_cs
);
2511 HeapFree(GetProcessHeap(), 0, unix_name
);
2516 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2518 static const WCHAR slashW
[] = {'\\','\0'};
2520 WCHAR windowsdir
[MAX_PATH
];
2523 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2524 strcatW(windowsdir
, fontsW
);
2525 strcatW(windowsdir
, slashW
);
2526 strcatW(windowsdir
, file
);
2527 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2528 EnterCriticalSection( &freetype_cs
);
2529 ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2530 LeaveCriticalSection( &freetype_cs
);
2531 HeapFree(GetProcessHeap(), 0, unixname
);
2536 static void load_system_fonts(void)
2539 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2540 const WCHAR
* const *value
;
2542 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2545 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2546 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2547 strcatW(windowsdir
, fontsW
);
2548 for(value
= SystemFontValues
; *value
; value
++) {
2549 dlen
= sizeof(data
);
2550 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2554 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2555 if((unixname
= wine_get_unix_file_name(pathW
))) {
2556 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2557 HeapFree(GetProcessHeap(), 0, unixname
);
2560 load_font_from_data_dir(data
);
2567 /*************************************************************
2569 * This adds registry entries for any externally loaded fonts
2570 * (fonts from fontconfig or FontDirs). It also deletes entries
2571 * of no longer existing fonts.
2574 static void update_reg_entries(void)
2576 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2581 struct list
*family_elem_ptr
, *face_elem_ptr
;
2583 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2584 static const WCHAR spaceW
[] = {' ', '\0'};
2587 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2588 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2589 ERR("Can't create Windows font reg key\n");
2593 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2594 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2595 ERR("Can't create Windows font reg key\n");
2599 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2600 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2601 ERR("Can't create external font reg key\n");
2605 /* enumerate the fonts and add external ones to the two keys */
2607 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2608 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2609 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2610 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2611 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2612 if(!face
->external
) continue;
2614 if (!(face
->ntmFlags
& NTM_REGULAR
))
2615 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2616 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2617 strcpyW(valueW
, family
->FamilyName
);
2618 if(len
!= len_fam
) {
2619 strcatW(valueW
, spaceW
);
2620 strcatW(valueW
, face
->StyleName
);
2622 strcatW(valueW
, TrueType
);
2624 file
= wine_get_dos_file_name(face
->file
);
2626 len
= strlenW(file
) + 1;
2629 if((path
= strrchr(face
->file
, '/')) == NULL
)
2633 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2635 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2636 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2638 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2639 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2640 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2642 HeapFree(GetProcessHeap(), 0, file
);
2643 HeapFree(GetProcessHeap(), 0, valueW
);
2647 if(external_key
) RegCloseKey(external_key
);
2648 if(win9x_key
) RegCloseKey(win9x_key
);
2649 if(winnt_key
) RegCloseKey(winnt_key
);
2653 static void delete_external_font_keys(void)
2655 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2656 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2660 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2661 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2662 ERR("Can't create Windows font reg key\n");
2666 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2667 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2668 ERR("Can't create Windows font reg key\n");
2672 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2673 ERR("Can't create external font reg key\n");
2677 /* Delete all external fonts added last time */
2679 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2680 &valuelen
, &datalen
, NULL
, NULL
);
2681 valuelen
++; /* returned value doesn't include room for '\0' */
2682 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2683 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2685 dlen
= datalen
* sizeof(WCHAR
);
2688 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2689 &dlen
) == ERROR_SUCCESS
) {
2691 RegDeleteValueW(winnt_key
, valueW
);
2692 RegDeleteValueW(win9x_key
, valueW
);
2693 /* reset dlen and vlen */
2697 HeapFree(GetProcessHeap(), 0, data
);
2698 HeapFree(GetProcessHeap(), 0, valueW
);
2700 /* Delete the old external fonts key */
2701 RegCloseKey(external_key
);
2702 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2705 if(win9x_key
) RegCloseKey(win9x_key
);
2706 if(winnt_key
) RegCloseKey(winnt_key
);
2709 /*************************************************************
2710 * WineEngAddFontResourceEx
2713 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2719 if (ft_handle
) /* do it only if we have freetype up and running */
2724 FIXME("Ignoring flags %x\n", flags
);
2726 if((unixname
= wine_get_unix_file_name(file
)))
2728 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2730 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2731 EnterCriticalSection( &freetype_cs
);
2732 ret
= AddFontFileToList(unixname
, NULL
, NULL
, addfont_flags
);
2733 LeaveCriticalSection( &freetype_cs
);
2734 HeapFree(GetProcessHeap(), 0, unixname
);
2736 if (!ret
&& !strchrW(file
, '\\')) {
2737 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2738 ret
= load_font_from_winfonts_dir(file
);
2740 /* Try in datadir/fonts (or builddir/fonts),
2741 * needed for Magic the Gathering Online
2743 ret
= load_font_from_data_dir(file
);
2750 /*************************************************************
2751 * WineEngAddFontMemResourceEx
2754 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2758 if (ft_handle
) /* do it only if we have freetype up and running */
2760 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2762 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2763 memcpy(pFontCopy
, pbFont
, cbFont
);
2765 EnterCriticalSection( &freetype_cs
);
2766 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2767 LeaveCriticalSection( &freetype_cs
);
2771 TRACE("AddFontToList failed\n");
2772 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2775 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2776 * For now return something unique but quite random
2778 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2779 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2786 /*************************************************************
2787 * WineEngRemoveFontResourceEx
2790 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2793 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2797 static const struct nls_update_font_list
2799 UINT ansi_cp
, oem_cp
;
2800 const char *oem
, *fixed
, *system
;
2801 const char *courier
, *serif
, *small
, *sserif
;
2802 /* these are for font substitutes */
2803 const char *shelldlg
, *tmsrmn
;
2804 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
2808 const char *from
, *to
;
2809 } arial_0
, courier_new_0
, times_new_roman_0
;
2810 } nls_update_font_list
[] =
2812 /* Latin 1 (United States) */
2813 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2814 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2815 "Tahoma","Times New Roman",
2816 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2819 /* Latin 1 (Multilingual) */
2820 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2821 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2822 "Tahoma","Times New Roman", /* FIXME unverified */
2823 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2826 /* Eastern Europe */
2827 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2828 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2829 "Tahoma","Times New Roman", /* FIXME unverified */
2830 "Fixedsys,238", "System,238",
2831 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2832 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2833 { "Arial CE,0", "Arial,238" },
2834 { "Courier New CE,0", "Courier New,238" },
2835 { "Times New Roman CE,0", "Times New Roman,238" }
2838 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2839 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2840 "Tahoma","Times New Roman", /* FIXME unverified */
2841 "Fixedsys,204", "System,204",
2842 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2843 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2844 { "Arial Cyr,0", "Arial,204" },
2845 { "Courier New Cyr,0", "Courier New,204" },
2846 { "Times New Roman Cyr,0", "Times New Roman,204" }
2849 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2850 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2851 "Tahoma","Times New Roman", /* FIXME unverified */
2852 "Fixedsys,161", "System,161",
2853 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2854 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2855 { "Arial Greek,0", "Arial,161" },
2856 { "Courier New Greek,0", "Courier New,161" },
2857 { "Times New Roman Greek,0", "Times New Roman,161" }
2860 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2861 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2862 "Tahoma","Times New Roman", /* FIXME unverified */
2863 "Fixedsys,162", "System,162",
2864 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2865 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2866 { "Arial Tur,0", "Arial,162" },
2867 { "Courier New Tur,0", "Courier New,162" },
2868 { "Times New Roman Tur,0", "Times New Roman,162" }
2871 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2872 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2873 "Tahoma","Times New Roman", /* FIXME unverified */
2874 "Fixedsys,177", "System,177",
2875 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2876 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2880 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2881 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2882 "Tahoma","Times New Roman", /* FIXME unverified */
2883 "Fixedsys,178", "System,178",
2884 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2885 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2889 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2890 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2891 "Tahoma","Times New Roman", /* FIXME unverified */
2892 "Fixedsys,186", "System,186",
2893 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2894 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2895 { "Arial Baltic,0", "Arial,186" },
2896 { "Courier New Baltic,0", "Courier New,186" },
2897 { "Times New Roman Baltic,0", "Times New Roman,186" }
2900 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2901 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2902 "Tahoma","Times New Roman", /* FIXME unverified */
2903 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2907 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2908 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2909 "Tahoma","Times New Roman", /* FIXME unverified */
2910 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2914 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2915 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2916 "MS UI Gothic","MS Serif",
2917 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2920 /* Chinese Simplified */
2921 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2922 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2923 "SimSun", "NSimSun",
2924 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2928 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2929 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2931 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2934 /* Chinese Traditional */
2935 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2936 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2937 "PMingLiU", "MingLiU",
2938 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2943 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
2945 return ( ansi_cp
== 932 /* CP932 for Japanese */
2946 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
2947 || ansi_cp
== 949 /* CP949 for Korean */
2948 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
2951 static inline HKEY
create_fonts_NT_registry_key(void)
2955 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
2956 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2960 static inline HKEY
create_fonts_9x_registry_key(void)
2964 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
2965 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2969 static inline HKEY
create_config_fonts_registry_key(void)
2973 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
2974 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
2978 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
2980 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
2981 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
2982 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
2983 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
2986 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
2989 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
2991 RegDeleteValueA(hkey
, name
);
2994 static void update_font_info(void)
2996 char buf
[40], cpbuf
[40];
2999 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3002 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3005 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3006 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3007 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3008 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3009 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3011 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3012 if (is_dbcs_ansi_cp(ansi_cp
))
3013 use_default_fallback
= TRUE
;
3016 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3018 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
3023 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
3025 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
3027 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3030 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3034 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3035 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3037 hkey
= create_config_fonts_registry_key();
3038 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3039 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3040 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3043 hkey
= create_fonts_NT_registry_key();
3044 add_font_list(hkey
, &nls_update_font_list
[i
]);
3047 hkey
= create_fonts_9x_registry_key();
3048 add_font_list(hkey
, &nls_update_font_list
[i
]);
3051 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3053 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3054 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3055 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3056 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3058 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3059 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3060 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3061 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3062 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3063 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3064 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3065 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3067 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3068 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3069 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3077 /* Delete the FontSubstitutes from other locales */
3078 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3080 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3081 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3082 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3088 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3091 static BOOL
init_freetype(void)
3093 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3096 "Wine cannot find the FreeType font library. To enable Wine to\n"
3097 "use TrueType fonts please install a version of FreeType greater than\n"
3098 "or equal to 2.0.5.\n"
3099 "http://www.freetype.org\n");
3103 #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;}
3105 LOAD_FUNCPTR(FT_Done_Face
)
3106 LOAD_FUNCPTR(FT_Get_Char_Index
)
3107 LOAD_FUNCPTR(FT_Get_First_Char
)
3108 LOAD_FUNCPTR(FT_Get_Module
)
3109 LOAD_FUNCPTR(FT_Get_Next_Char
)
3110 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3111 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3112 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3113 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3114 LOAD_FUNCPTR(FT_Init_FreeType
)
3115 LOAD_FUNCPTR(FT_Library_Version
)
3116 LOAD_FUNCPTR(FT_Load_Glyph
)
3117 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3118 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3119 #ifndef FT_MULFIX_INLINED
3120 LOAD_FUNCPTR(FT_MulFix
)
3122 LOAD_FUNCPTR(FT_New_Face
)
3123 LOAD_FUNCPTR(FT_New_Memory_Face
)
3124 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3125 LOAD_FUNCPTR(FT_Outline_Transform
)
3126 LOAD_FUNCPTR(FT_Outline_Translate
)
3127 LOAD_FUNCPTR(FT_Render_Glyph
)
3128 LOAD_FUNCPTR(FT_Select_Charmap
)
3129 LOAD_FUNCPTR(FT_Set_Charmap
)
3130 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3131 LOAD_FUNCPTR(FT_Vector_Transform
)
3132 LOAD_FUNCPTR(FT_Vector_Unit
)
3134 /* Don't warn if these ones are missing */
3135 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3136 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3137 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3140 if(pFT_Init_FreeType(&library
) != 0) {
3141 ERR("Can't init FreeType library\n");
3142 wine_dlclose(ft_handle
, NULL
, 0);
3146 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3148 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3149 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3150 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3151 ((FT_Version
.patch
) & 0x0000ff);
3153 font_driver
= &freetype_funcs
;
3158 "Wine cannot find certain functions that it needs inside the FreeType\n"
3159 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3160 "FreeType to at least version 2.1.4.\n"
3161 "http://www.freetype.org\n");
3162 wine_dlclose(ft_handle
, NULL
, 0);
3167 static void init_font_list(void)
3169 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3170 static const WCHAR pathW
[] = {'P','a','t','h',0};
3172 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3173 WCHAR windowsdir
[MAX_PATH
];
3175 const char *data_dir
;
3177 delete_external_font_keys();
3179 /* load the system bitmap fonts */
3180 load_system_fonts();
3182 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3183 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3184 strcatW(windowsdir
, fontsW
);
3185 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3187 ReadFontDir(unixname
, FALSE
);
3188 HeapFree(GetProcessHeap(), 0, unixname
);
3191 /* load the system truetype fonts */
3192 data_dir
= wine_get_data_dir();
3193 if (!data_dir
) data_dir
= wine_get_build_dir();
3194 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3196 strcpy(unixname
, data_dir
);
3197 strcat(unixname
, "/fonts/");
3198 ReadFontDir(unixname
, TRUE
);
3199 HeapFree(GetProcessHeap(), 0, unixname
);
3202 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3203 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3204 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3206 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3207 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3208 &hkey
) == ERROR_SUCCESS
)
3210 LPWSTR data
, valueW
;
3211 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3212 &valuelen
, &datalen
, NULL
, NULL
);
3214 valuelen
++; /* returned value doesn't include room for '\0' */
3215 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3216 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3219 dlen
= datalen
* sizeof(WCHAR
);
3221 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3222 &dlen
) == ERROR_SUCCESS
)
3224 if(data
[0] && (data
[1] == ':'))
3226 if((unixname
= wine_get_unix_file_name(data
)))
3228 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3229 HeapFree(GetProcessHeap(), 0, unixname
);
3232 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3234 WCHAR pathW
[MAX_PATH
];
3235 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3238 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3239 if((unixname
= wine_get_unix_file_name(pathW
)))
3241 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3242 HeapFree(GetProcessHeap(), 0, unixname
);
3245 load_font_from_data_dir(data
);
3247 /* reset dlen and vlen */
3252 HeapFree(GetProcessHeap(), 0, data
);
3253 HeapFree(GetProcessHeap(), 0, valueW
);
3257 #ifdef SONAME_LIBFONTCONFIG
3258 load_fontconfig_fonts();
3259 #elif defined(HAVE_CARBON_CARBON_H)
3263 /* then look in any directories that we've specified in the config file */
3264 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3265 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3271 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3273 len
+= sizeof(WCHAR
);
3274 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3275 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3277 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3278 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3279 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3280 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3285 LPSTR next
= strchr( ptr
, ':' );
3286 if (next
) *next
++ = 0;
3287 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3288 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3290 strcpy( unixname
, home
);
3291 strcat( unixname
, ptr
+ 1 );
3292 ReadFontDir( unixname
, TRUE
);
3293 HeapFree( GetProcessHeap(), 0, unixname
);
3296 ReadFontDir( ptr
, TRUE
);
3299 HeapFree( GetProcessHeap(), 0, valueA
);
3301 HeapFree( GetProcessHeap(), 0, valueW
);
3307 static BOOL
move_to_front(const WCHAR
*name
)
3309 Family
*family
, *cursor2
;
3310 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3312 if(!strcmpiW(family
->FamilyName
, name
))
3314 list_remove(&family
->entry
);
3315 list_add_head(&font_list
, &family
->entry
);
3322 static BOOL
set_default(const WCHAR
**name_list
)
3326 if (move_to_front(*name_list
)) return TRUE
;
3333 static void reorder_font_list(void)
3335 set_default( default_serif_list
);
3336 set_default( default_fixed_list
);
3337 set_default( default_sans_list
);
3340 /*************************************************************
3343 * Initialize FreeType library and create a list of available faces
3345 BOOL
WineEngInit(void)
3347 HKEY hkey_font_cache
;
3351 /* update locale dependent font info in registry */
3354 if(!init_freetype()) return FALSE
;
3356 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3358 ERR("Failed to create font mutex\n");
3361 WaitForSingleObject(font_mutex
, INFINITE
);
3363 create_font_cache_key(&hkey_font_cache
, &disposition
);
3365 if(disposition
== REG_CREATED_NEW_KEY
)
3368 load_font_list_from_cache(hkey_font_cache
);
3370 RegCloseKey(hkey_font_cache
);
3372 reorder_font_list();
3379 if(disposition
== REG_CREATED_NEW_KEY
)
3380 update_reg_entries();
3382 init_system_links();
3384 ReleaseMutex(font_mutex
);
3389 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3392 TT_HoriHeader
*pHori
;
3396 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3397 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3399 if(height
== 0) height
= 16;
3401 /* Calc. height of EM square:
3403 * For +ve lfHeight we have
3404 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3405 * Re-arranging gives:
3406 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3408 * For -ve lfHeight we have
3410 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3411 * with il = winAscent + winDescent - units_per_em]
3416 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3417 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3418 pHori
->Ascender
- pHori
->Descender
);
3420 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3421 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3429 static struct font_mapping
*map_font_file( const char *name
)
3431 struct font_mapping
*mapping
;
3435 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3436 if (fstat( fd
, &st
) == -1) goto error
;
3438 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3440 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3442 mapping
->refcount
++;
3447 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3450 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3453 if (mapping
->data
== MAP_FAILED
)
3455 HeapFree( GetProcessHeap(), 0, mapping
);
3458 mapping
->refcount
= 1;
3459 mapping
->dev
= st
.st_dev
;
3460 mapping
->ino
= st
.st_ino
;
3461 mapping
->size
= st
.st_size
;
3462 list_add_tail( &mappings_list
, &mapping
->entry
);
3470 static void unmap_font_file( struct font_mapping
*mapping
)
3472 if (!--mapping
->refcount
)
3474 list_remove( &mapping
->entry
);
3475 munmap( mapping
->data
, mapping
->size
);
3476 HeapFree( GetProcessHeap(), 0, mapping
);
3480 static LONG
load_VDMX(GdiFont
*, LONG
);
3482 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3489 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3493 if (!(font
->mapping
= map_font_file( face
->file
)))
3495 WARN("failed to map %s\n", debugstr_a(face
->file
));
3498 data_ptr
= font
->mapping
->data
;
3499 data_size
= font
->mapping
->size
;
3503 data_ptr
= face
->font_data_ptr
;
3504 data_size
= face
->font_data_size
;
3507 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3509 ERR("FT_New_Face rets %d\n", err
);
3513 /* set it here, as load_VDMX needs it */
3514 font
->ft_face
= ft_face
;
3516 if(FT_IS_SCALABLE(ft_face
)) {
3517 /* load the VDMX table if we have one */
3518 font
->ppem
= load_VDMX(font
, height
);
3520 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3521 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3523 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3524 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3526 font
->ppem
= height
;
3527 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3528 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3534 static int get_nearest_charset(Face
*face
, int *cp
)
3536 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3537 a single face with the requested charset. The idea is to check if
3538 the selected font supports the current ANSI codepage, if it does
3539 return the corresponding charset, else return the first charset */
3542 int acp
= GetACP(), i
;
3546 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3547 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
3548 return csi
.ciCharset
;
3550 for(i
= 0; i
< 32; i
++) {
3552 if(face
->fs
.fsCsb
[0] & fs0
) {
3553 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3555 return csi
.ciCharset
;
3558 FIXME("TCI failing on %x\n", fs0
);
3562 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3563 face
->fs
.fsCsb
[0], face
->file
);
3565 return DEFAULT_CHARSET
;
3568 static GdiFont
*alloc_font(void)
3570 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3572 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3573 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3575 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3576 ret
->total_kern_pairs
= (DWORD
)-1;
3577 ret
->kern_pairs
= NULL
;
3578 list_init(&ret
->hfontlist
);
3579 list_init(&ret
->child_fonts
);
3583 static void free_font(GdiFont
*font
)
3585 struct list
*cursor
, *cursor2
;
3588 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3590 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3591 list_remove(cursor
);
3593 free_font(child
->font
);
3594 HeapFree(GetProcessHeap(), 0, child
);
3597 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3599 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3600 DeleteObject(hfontlist
->hfont
);
3601 list_remove(&hfontlist
->entry
);
3602 HeapFree(GetProcessHeap(), 0, hfontlist
);
3605 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3606 if (font
->mapping
) unmap_font_file( font
->mapping
);
3607 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3608 HeapFree(GetProcessHeap(), 0, font
->potm
);
3609 HeapFree(GetProcessHeap(), 0, font
->name
);
3610 for (i
= 0; i
< font
->gmsize
; i
++)
3611 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3612 HeapFree(GetProcessHeap(), 0, font
->gm
);
3613 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3614 HeapFree(GetProcessHeap(), 0, font
);
3618 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3620 FT_Face ft_face
= font
->ft_face
;
3624 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3631 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3633 /* make sure value of len is the value freetype says it needs */
3636 FT_ULong needed
= 0;
3637 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3638 if( !err
&& needed
< len
) len
= needed
;
3640 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3643 TRACE("Can't find table %c%c%c%c\n",
3644 /* bytes were reversed */
3645 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
3646 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
3652 /*************************************************************
3655 * load the vdmx entry for the specified height
3658 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3659 ( ( (FT_ULong)_x4 << 24 ) | \
3660 ( (FT_ULong)_x3 << 16 ) | \
3661 ( (FT_ULong)_x2 << 8 ) | \
3664 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3679 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
3683 BYTE devXRatio
, devYRatio
;
3684 USHORT numRecs
, numRatios
;
3685 DWORD result
, offset
= -1;
3689 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
3691 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
3694 /* FIXME: need the real device aspect ratio */
3698 numRecs
= GET_BE_WORD(hdr
[1]);
3699 numRatios
= GET_BE_WORD(hdr
[2]);
3701 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
3702 for(i
= 0; i
< numRatios
; i
++) {
3705 offset
= (3 * 2) + (i
* sizeof(Ratios
));
3706 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
3709 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
3711 if((ratio
.xRatio
== 0 &&
3712 ratio
.yStartRatio
== 0 &&
3713 ratio
.yEndRatio
== 0) ||
3714 (devXRatio
== ratio
.xRatio
&&
3715 devYRatio
>= ratio
.yStartRatio
&&
3716 devYRatio
<= ratio
.yEndRatio
))
3718 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
3719 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
3720 offset
= GET_BE_WORD(tmp
);
3726 FIXME("No suitable ratio found\n");
3730 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
3732 BYTE startsz
, endsz
;
3735 recs
= GET_BE_WORD(group
.recs
);
3736 startsz
= group
.startsz
;
3737 endsz
= group
.endsz
;
3739 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
3741 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
3742 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
3743 if(result
== GDI_ERROR
) {
3744 FIXME("Failed to retrieve vTable\n");
3749 for(i
= 0; i
< recs
; i
++) {
3750 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3751 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3752 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3754 if(yMax
+ -yMin
== height
) {
3757 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3760 if(yMax
+ -yMin
> height
) {
3763 goto end
; /* failed */
3765 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
3766 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
3767 ppem
= GET_BE_WORD(vTable
[i
* 3]);
3768 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
3774 TRACE("ppem not found for height %d\n", height
);
3778 HeapFree(GetProcessHeap(), 0, vTable
);
3784 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
3786 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
3787 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
3788 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
3789 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
3790 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
3793 static void calc_hash(FONT_DESC
*pfd
)
3795 DWORD hash
= 0, *ptr
, two_chars
;
3799 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
3801 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
3803 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
3805 pwc
= (WCHAR
*)&two_chars
;
3807 *pwc
= toupperW(*pwc
);
3809 *pwc
= toupperW(*pwc
);
3813 hash
^= !pfd
->can_use_bitmap
;
3818 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
3823 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
3827 fd
.can_use_bitmap
= can_use_bitmap
;
3830 /* try the child list */
3831 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
3832 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3833 if(!fontcmp(ret
, &fd
)) {
3834 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3835 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3836 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3837 if(hflist
->hfont
== hfont
)
3843 /* try the in-use list */
3844 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
3845 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3846 if(!fontcmp(ret
, &fd
)) {
3847 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3848 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
3849 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3850 if(hflist
->hfont
== hfont
)
3853 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3854 hflist
->hfont
= hfont
;
3855 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3860 /* then the unused list */
3861 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3862 while(font_elem_ptr
) {
3863 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3864 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3865 if(!fontcmp(ret
, &fd
)) {
3866 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
3867 assert(list_empty(&ret
->hfontlist
));
3868 TRACE("Found %p in unused list\n", ret
);
3869 list_remove(&ret
->entry
);
3870 list_add_head(&gdi_font_list
, &ret
->entry
);
3871 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
3872 hflist
->hfont
= hfont
;
3873 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
3880 static void add_to_cache(GdiFont
*font
)
3882 static DWORD cache_num
= 1;
3884 font
->cache_num
= cache_num
++;
3885 list_add_head(&gdi_font_list
, &font
->entry
);
3888 /*************************************************************
3889 * create_child_font_list
3891 static BOOL
create_child_font_list(GdiFont
*font
)
3894 SYSTEM_LINKS
*font_link
;
3895 CHILD_FONT
*font_link_entry
, *new_child
;
3899 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
3900 font_name
= psub
? psub
->to
.name
: font
->name
;
3901 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3903 if(!strcmpiW(font_link
->font_name
, font_name
))
3905 TRACE("found entry in system list\n");
3906 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3908 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3909 new_child
->face
= font_link_entry
->face
;
3910 new_child
->font
= NULL
;
3911 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3912 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3919 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3920 * Sans Serif. This is how asian windows get default fallbacks for fonts
3922 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
3923 font
->charset
!= OEM_CHARSET
&&
3924 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
3925 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
3927 if(!strcmpiW(font_link
->font_name
,szDefaultFallbackLink
))
3929 TRACE("found entry in default fallback list\n");
3930 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
3932 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
3933 new_child
->face
= font_link_entry
->face
;
3934 new_child
->font
= NULL
;
3935 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
3936 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
3946 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
3948 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
3950 if (pFT_Set_Charmap
)
3953 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
3955 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
3957 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
3959 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
3961 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3962 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
3964 switch (ft_face
->charmaps
[i
]->platform_id
)
3967 cmap_def
= ft_face
->charmaps
[i
];
3969 case 0: /* Apple Unicode */
3970 cmap0
= ft_face
->charmaps
[i
];
3972 case 1: /* Macintosh */
3973 cmap1
= ft_face
->charmaps
[i
];
3976 cmap2
= ft_face
->charmaps
[i
];
3978 case 3: /* Microsoft */
3979 cmap3
= ft_face
->charmaps
[i
];
3984 if (cmap3
) /* prefer Microsoft cmap table */
3985 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
3987 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
3989 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
3991 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
3993 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
3995 return ft_err
== FT_Err_Ok
;
3998 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4002 /*************************************************************
4005 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4006 LPCWSTR output
, const DEVMODEW
*devmode
)
4008 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4010 if (!physdev
) return FALSE
;
4011 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4016 /*************************************************************
4019 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4021 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4022 HeapFree( GetProcessHeap(), 0, physdev
);
4027 /*************************************************************
4028 * freetype_SelectFont
4030 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
4032 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4034 Face
*face
, *best
, *best_bitmap
;
4035 Family
*family
, *last_resort_family
;
4036 struct list
*family_elem_ptr
, *face_elem_ptr
;
4037 INT height
, width
= 0;
4038 unsigned int score
= 0, new_score
;
4039 signed int diff
= 0, newdiff
;
4040 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4045 FontSubst
*psub
= NULL
;
4046 DC
*dc
= get_dc_ptr( dev
->hdc
);
4048 if (!hfont
) /* notification that the font has been changed by another driver */
4051 physdev
->font
= NULL
;
4052 release_dc_ptr( dc
);
4056 GetObjectW( hfont
, sizeof(lf
), &lf
);
4057 lf
.lfWidth
= abs(lf
.lfWidth
);
4059 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4061 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4062 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4063 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4066 if(dc
->GraphicsMode
== GM_ADVANCED
)
4068 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4069 /* Try to avoid not necessary glyph transformations */
4070 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4072 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4073 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4074 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4079 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4080 font scaling abilities. */
4081 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4082 dcmat
.eM21
= dcmat
.eM12
= 0;
4083 if (dc
->vport2WorldValid
)
4085 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4086 lf
.lfOrientation
= -lf
.lfOrientation
;
4087 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4088 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4092 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4093 dcmat
.eM21
, dcmat
.eM22
);
4096 EnterCriticalSection( &freetype_cs
);
4098 /* check the cache first */
4099 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4100 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4104 if(list_empty(&font_list
)) /* No fonts installed */
4106 TRACE("No fonts installed\n");
4110 TRACE("not in cache\n");
4113 ret
->font_desc
.matrix
= dcmat
;
4114 ret
->font_desc
.lf
= lf
;
4115 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4116 calc_hash(&ret
->font_desc
);
4117 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4118 hflist
->hfont
= hfont
;
4119 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4121 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4122 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4123 original value lfCharSet. Note this is a special case for
4124 Symbol and doesn't happen at least for "Wingdings*" */
4126 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4127 lf
.lfCharSet
= SYMBOL_CHARSET
;
4129 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4130 switch(lf
.lfCharSet
) {
4131 case DEFAULT_CHARSET
:
4132 csi
.fs
.fsCsb
[0] = 0;
4135 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4136 csi
.fs
.fsCsb
[0] = 0;
4142 if(lf
.lfFaceName
[0] != '\0') {
4143 SYSTEM_LINKS
*font_link
;
4144 CHILD_FONT
*font_link_entry
;
4145 LPWSTR FaceName
= lf
.lfFaceName
;
4147 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4150 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4151 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4152 if (psub
->to
.charset
!= -1)
4153 lf
.lfCharSet
= psub
->to
.charset
;
4156 /* We want a match on name and charset or just name if
4157 charset was DEFAULT_CHARSET. If the latter then
4158 we fixup the returned charset later in get_nearest_charset
4159 where we'll either use the charset of the current ansi codepage
4160 or if that's unavailable the first charset that the font supports.
4162 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4163 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4164 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4165 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4167 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4168 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4169 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
4170 if(face
->scalable
|| can_use_bitmap
)
4176 /* Search by full face name. */
4177 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4178 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4179 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4180 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4181 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4182 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]))
4184 if(face
->scalable
|| can_use_bitmap
)
4191 * Try check the SystemLink list first for a replacement font.
4192 * We may find good replacements there.
4194 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4196 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4197 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4199 TRACE("found entry in system list\n");
4200 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4202 face
= font_link_entry
->face
;
4203 family
= face
->family
;
4204 if(csi
.fs
.fsCsb
[0] &
4205 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
4207 if(face
->scalable
|| can_use_bitmap
)
4215 psub
= NULL
; /* substitution is no more relevant */
4217 /* If requested charset was DEFAULT_CHARSET then try using charset
4218 corresponding to the current ansi codepage */
4219 if (!csi
.fs
.fsCsb
[0])
4222 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4223 FIXME("TCI failed on codepage %d\n", acp
);
4224 csi
.fs
.fsCsb
[0] = 0;
4226 lf
.lfCharSet
= csi
.ciCharset
;
4229 want_vertical
= (lf
.lfFaceName
[0] == '@');
4231 /* Face families are in the top 4 bits of lfPitchAndFamily,
4232 so mask with 0xF0 before testing */
4234 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4235 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4236 strcpyW(lf
.lfFaceName
, defFixed
);
4237 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4238 strcpyW(lf
.lfFaceName
, defSerif
);
4239 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4240 strcpyW(lf
.lfFaceName
, defSans
);
4242 strcpyW(lf
.lfFaceName
, defSans
);
4243 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4244 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4245 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4246 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4247 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4248 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
4249 if(face
->scalable
|| can_use_bitmap
)
4255 last_resort_family
= NULL
;
4256 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4257 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4258 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4259 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4260 if(face
->vertical
== want_vertical
&&
4261 (csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))) {
4264 if(can_use_bitmap
&& !last_resort_family
)
4265 last_resort_family
= family
;
4270 if(last_resort_family
) {
4271 family
= last_resort_family
;
4272 csi
.fs
.fsCsb
[0] = 0;
4276 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4277 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4278 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4279 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4280 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4281 csi
.fs
.fsCsb
[0] = 0;
4282 WARN("just using first face for now\n");
4285 if(can_use_bitmap
&& !last_resort_family
)
4286 last_resort_family
= family
;
4289 if(!last_resort_family
) {
4290 FIXME("can't find a single appropriate font - bailing\n");
4296 WARN("could only find a bitmap font - this will probably look awful!\n");
4297 family
= last_resort_family
;
4298 csi
.fs
.fsCsb
[0] = 0;
4301 it
= lf
.lfItalic
? 1 : 0;
4302 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4304 height
= lf
.lfHeight
;
4306 face
= best
= best_bitmap
= NULL
;
4307 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
4309 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
4313 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4314 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4315 new_score
= (italic
^ it
) + (bold
^ bd
);
4316 if(!best
|| new_score
<= score
)
4318 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4319 italic
, bold
, it
, bd
);
4322 if(best
->scalable
&& score
== 0) break;
4326 newdiff
= height
- (signed int)(best
->size
.height
);
4328 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4329 if(!best_bitmap
|| new_score
< score
||
4330 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4332 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4335 if(score
== 0 && diff
== 0) break;
4342 face
= best
->scalable
? best
: best_bitmap
;
4343 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4344 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4347 height
= lf
.lfHeight
;
4351 if(csi
.fs
.fsCsb
[0]) {
4352 ret
->charset
= lf
.lfCharSet
;
4353 ret
->codepage
= csi
.ciACP
;
4356 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
4358 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4359 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4361 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4363 if(!face
->scalable
) {
4364 /* Windows uses integer scaling factors for bitmap fonts */
4365 INT scale
, scaled_height
;
4366 GdiFont
*cachedfont
;
4368 /* FIXME: rotation of bitmap fonts is ignored */
4369 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4371 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4372 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4373 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4374 /* As we changed the matrix, we need to search the cache for the font again,
4375 * otherwise we might explode the cache. */
4376 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4377 TRACE("Found cached font after non-scalable matrix rescale!\n");
4382 calc_hash(&ret
->font_desc
);
4384 if (height
!= 0) height
= diff
;
4385 height
+= face
->size
.height
;
4387 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4388 scaled_height
= scale
* face
->size
.height
;
4389 /* Only jump to the next height if the difference <= 25% original height */
4390 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4391 /* The jump between unscaled and doubled is delayed by 1 */
4392 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4393 ret
->scale_y
= scale
;
4395 width
= face
->size
.x_ppem
>> 6;
4396 height
= face
->size
.y_ppem
>> 6;
4400 TRACE("font scale y: %f\n", ret
->scale_y
);
4402 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4411 ret
->ntmFlags
= face
->ntmFlags
;
4413 if (ret
->charset
== SYMBOL_CHARSET
&&
4414 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4417 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4421 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4424 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4425 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4426 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4427 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4428 create_child_font_list(ret
);
4430 if (face
->vertical
) /* We need to try to load the GSUB table */
4432 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4433 if (length
!= GDI_ERROR
)
4435 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4436 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4437 TRACE("Loaded GSUB table of %i bytes\n",length
);
4441 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4448 physdev
->font
= ret
;
4450 LeaveCriticalSection( &freetype_cs
);
4451 release_dc_ptr( dc
);
4452 return ret
? hfont
: 0;
4455 static void dump_gdi_font_list(void)
4458 struct list
*elem_ptr
;
4460 TRACE("---------- gdiFont Cache ----------\n");
4461 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4462 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4463 TRACE("gdiFont=%p %s %d\n",
4464 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4467 TRACE("---------- Unused gdiFont Cache ----------\n");
4468 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4469 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4470 TRACE("gdiFont=%p %s %d\n",
4471 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4474 TRACE("---------- Child gdiFont Cache ----------\n");
4475 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4476 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4477 TRACE("gdiFont=%p %s %d\n",
4478 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4482 /*************************************************************
4483 * WineEngDestroyFontInstance
4485 * free the gdiFont associated with this handle
4488 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4493 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4497 EnterCriticalSection( &freetype_cs
);
4499 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4501 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4502 while(hfontlist_elem_ptr
) {
4503 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4504 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4505 if(hflist
->hfont
== handle
) {
4506 TRACE("removing child font %p from child list\n", gdiFont
);
4507 list_remove(&gdiFont
->entry
);
4508 LeaveCriticalSection( &freetype_cs
);
4514 TRACE("destroying hfont=%p\n", handle
);
4516 dump_gdi_font_list();
4518 font_elem_ptr
= list_head(&gdi_font_list
);
4519 while(font_elem_ptr
) {
4520 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4521 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4523 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4524 while(hfontlist_elem_ptr
) {
4525 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4526 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4527 if(hflist
->hfont
== handle
) {
4528 list_remove(&hflist
->entry
);
4529 HeapFree(GetProcessHeap(), 0, hflist
);
4533 if(list_empty(&gdiFont
->hfontlist
)) {
4534 TRACE("Moving to Unused list\n");
4535 list_remove(&gdiFont
->entry
);
4536 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4541 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4542 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4543 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4544 while(font_elem_ptr
) {
4545 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4546 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4547 TRACE("freeing %p\n", gdiFont
);
4548 list_remove(&gdiFont
->entry
);
4551 LeaveCriticalSection( &freetype_cs
);
4555 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4562 id
+= IDS_FIRST_SCRIPT
;
4563 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4564 if (!rsrc
) return 0;
4565 hMem
= LoadResource( gdi32_module
, rsrc
);
4566 if (!hMem
) return 0;
4568 p
= LockResource( hMem
);
4570 while (id
--) p
+= *p
+ 1;
4572 i
= min(LF_FACESIZE
- 1, *p
);
4573 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4579 /***************************************************
4580 * create_enum_charset_list
4582 * This function creates charset enumeration list because in DEFAULT_CHARSET
4583 * case, the ANSI codepage's charset takes precedence over other charsets.
4584 * This function works as a filter other than DEFAULT_CHARSET case.
4586 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4591 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4592 csi
.fs
.fsCsb
[0] != 0) {
4593 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4594 list
->element
[n
].charset
= csi
.ciCharset
;
4595 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4598 else { /* charset is DEFAULT_CHARSET or invalid. */
4601 /* Set the current codepage's charset as the first element. */
4603 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4604 csi
.fs
.fsCsb
[0] != 0) {
4605 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4606 list
->element
[n
].charset
= csi
.ciCharset
;
4607 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4611 /* Fill out left elements. */
4612 for (i
= 0; i
< 32; i
++) {
4614 fs
.fsCsb
[0] = 1L << i
;
4616 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
4617 continue; /* skip, already added. */
4618 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
4619 continue; /* skip, this is an invalid fsCsb bit. */
4621 list
->element
[n
].mask
= fs
.fsCsb
[0];
4622 list
->element
[n
].charset
= csi
.ciCharset
;
4623 load_script_name( i
, list
->element
[n
].name
);
4632 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
4633 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
4638 if (face
->cached_enum_data
)
4641 *pelf
= face
->cached_enum_data
->elf
;
4642 *pntm
= face
->cached_enum_data
->ntm
;
4643 *ptype
= face
->cached_enum_data
->type
;
4647 font
= alloc_font();
4649 if(face
->scalable
) {
4650 height
= -2048; /* 2048 is the most common em size */
4653 height
= face
->size
.y_ppem
>> 6;
4654 width
= face
->size
.x_ppem
>> 6;
4656 font
->scale_y
= 1.0;
4658 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
4664 font
->name
= strdupW(face
->family
->FamilyName
);
4665 font
->ntmFlags
= face
->ntmFlags
;
4667 if (get_outline_text_metrics(font
))
4669 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
4671 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
4673 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
4674 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
4676 lstrcpynW(pelf
->elfFullName
,
4677 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
4679 lstrcpynW(pelf
->elfStyle
,
4680 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
4685 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
4687 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
4689 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
4691 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
4693 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
4694 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
4697 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
4698 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
4699 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4700 pntm
->ntmFontSig
= face
->fs
;
4702 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
4704 pelf
->elfLogFont
.lfEscapement
= 0;
4705 pelf
->elfLogFont
.lfOrientation
= 0;
4706 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
4707 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
4708 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
4709 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
4710 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
4711 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
4712 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
4713 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
4714 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
4715 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
4716 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
4719 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
4720 *ptype
|= TRUETYPE_FONTTYPE
;
4721 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
4722 *ptype
|= DEVICE_FONTTYPE
;
4723 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
4724 *ptype
|= RASTER_FONTTYPE
;
4726 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
4727 if (face
->cached_enum_data
)
4729 face
->cached_enum_data
->elf
= *pelf
;
4730 face
->cached_enum_data
->ntm
= *pntm
;
4731 face
->cached_enum_data
->type
= *ptype
;
4737 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
4739 struct list
*face_elem_ptr
;
4741 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
4743 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
)
4745 static const WCHAR spaceW
[] = { ' ',0 };
4746 WCHAR full_family_name
[LF_FULLFACESIZE
];
4747 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4749 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4751 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4752 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
4756 strcpyW(full_family_name
, family
->FamilyName
);
4757 strcatW(full_family_name
, spaceW
);
4758 strcatW(full_family_name
, face
->StyleName
);
4759 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
4765 static BOOL
face_matches(Face
*face
, const LOGFONTW
*lf
)
4767 static const WCHAR spaceW
[] = { ' ',0 };
4768 WCHAR full_family_name
[LF_FULLFACESIZE
];
4770 if (!strcmpiW(lf
->lfFaceName
, face
->family
->FamilyName
)) return TRUE
;
4772 if (strlenW(face
->family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
4774 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4775 debugstr_w(face
->family
->FamilyName
), debugstr_w(face
->StyleName
));
4779 strcpyW(full_family_name
, face
->family
->FamilyName
);
4780 strcatW(full_family_name
, spaceW
);
4781 strcatW(full_family_name
, face
->StyleName
);
4782 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
4785 static BOOL
enum_face_charsets(Face
*face
, struct enum_charset_list
*list
,
4786 FONTENUMPROCW proc
, LPARAM lparam
)
4789 NEWTEXTMETRICEXW ntm
;
4793 GetEnumStructs(face
, &elf
, &ntm
, &type
);
4794 for(i
= 0; i
< list
->total
; i
++) {
4795 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
4796 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
4797 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
4798 i
= list
->total
; /* break out of loop after enumeration */
4799 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
4802 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
4803 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
4804 if (!elf
.elfScript
[0])
4805 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
4807 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4808 debugstr_w(elf
.elfLogFont
.lfFaceName
),
4809 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
4810 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
4811 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
4812 ntm
.ntmTm
.ntmFlags
);
4813 /* release section before callback (FIXME) */
4814 LeaveCriticalSection( &freetype_cs
);
4815 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
4816 EnterCriticalSection( &freetype_cs
);
4821 /*************************************************************
4822 * freetype_EnumFonts
4824 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4828 struct list
*family_elem_ptr
, *face_elem_ptr
;
4830 struct enum_charset_list enum_charsets
;
4834 lf
.lfCharSet
= DEFAULT_CHARSET
;
4835 lf
.lfPitchAndFamily
= 0;
4836 lf
.lfFaceName
[0] = 0;
4840 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
4842 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
4845 EnterCriticalSection( &freetype_cs
);
4846 if(plf
->lfFaceName
[0]) {
4848 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
4851 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
4852 debugstr_w(psub
->to
.name
));
4854 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
4858 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4859 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4860 if(family_matches(family
, plf
)) {
4861 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
4862 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4863 if (!face_matches(face
, plf
)) continue;
4864 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4869 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4870 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4871 face_elem_ptr
= list_head(&family
->faces
);
4872 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4873 if (!enum_face_charsets(face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
4876 LeaveCriticalSection( &freetype_cs
);
4880 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
4882 pt
->x
.value
= vec
->x
>> 6;
4883 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
4884 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
4885 pt
->y
.value
= vec
->y
>> 6;
4886 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
4887 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
4891 /***************************************************
4892 * According to the MSDN documentation on WideCharToMultiByte,
4893 * certain codepages cannot set the default_used parameter.
4894 * This returns TRUE if the codepage can set that parameter, false else
4895 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4897 static BOOL
codepage_sets_default_used(UINT codepage
)
4911 * GSUB Table handling functions
4914 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
4916 const GSUB_CoverageFormat1
* cf1
;
4920 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
4922 int count
= GET_BE_WORD(cf1
->GlyphCount
);
4924 TRACE("Coverage Format 1, %i glyphs\n",count
);
4925 for (i
= 0; i
< count
; i
++)
4926 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
4930 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
4932 const GSUB_CoverageFormat2
* cf2
;
4935 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
4937 count
= GET_BE_WORD(cf2
->RangeCount
);
4938 TRACE("Coverage Format 2, %i ranges\n",count
);
4939 for (i
= 0; i
< count
; i
++)
4941 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
4943 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
4944 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
4946 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
4947 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
4953 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
4958 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4960 const GSUB_ScriptList
*script
;
4961 const GSUB_Script
*deflt
= NULL
;
4963 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4965 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4966 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4968 const GSUB_Script
*scr
;
4971 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4972 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4974 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4976 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4982 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4986 const GSUB_LangSys
*Lang
;
4988 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4990 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4992 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4993 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4995 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4998 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5001 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5007 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5010 const GSUB_FeatureList
*feature
;
5011 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5013 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5014 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5016 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5017 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5019 const GSUB_Feature
*feat
;
5020 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5027 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5031 const GSUB_LookupList
*lookup
;
5032 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5034 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5035 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5037 const GSUB_LookupTable
*look
;
5038 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5039 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5040 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5041 if (GET_BE_WORD(look
->LookupType
) != 1)
5042 FIXME("We only handle SubType 1\n");
5047 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5049 const GSUB_SingleSubstFormat1
*ssf1
;
5050 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5051 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5052 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5054 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5055 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5056 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5058 TRACE(" Glyph 0x%x ->",glyph
);
5059 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5060 TRACE(" 0x%x\n",glyph
);
5065 const GSUB_SingleSubstFormat2
*ssf2
;
5069 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5070 offset
= GET_BE_WORD(ssf1
->Coverage
);
5071 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5072 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5073 TRACE(" Coverage index %i\n",index
);
5076 TRACE(" Glyph is 0x%x ->",glyph
);
5077 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5078 TRACE("0x%x\n",glyph
);
5087 static const char* get_opentype_script(const GdiFont
*font
)
5090 * I am not sure if this is the correct way to generate our script tag
5093 switch (font
->charset
)
5095 case ANSI_CHARSET
: return "latn";
5096 case BALTIC_CHARSET
: return "latn"; /* ?? */
5097 case CHINESEBIG5_CHARSET
: return "hani";
5098 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5099 case GB2312_CHARSET
: return "hani";
5100 case GREEK_CHARSET
: return "grek";
5101 case HANGUL_CHARSET
: return "hang";
5102 case RUSSIAN_CHARSET
: return "cyrl";
5103 case SHIFTJIS_CHARSET
: return "kana";
5104 case TURKISH_CHARSET
: return "latn"; /* ?? */
5105 case VIETNAMESE_CHARSET
: return "latn";
5106 case JOHAB_CHARSET
: return "latn"; /* ?? */
5107 case ARABIC_CHARSET
: return "arab";
5108 case HEBREW_CHARSET
: return "hebr";
5109 case THAI_CHARSET
: return "thai";
5110 default: return "latn";
5114 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5116 const GSUB_Header
*header
;
5117 const GSUB_Script
*script
;
5118 const GSUB_LangSys
*language
;
5119 const GSUB_Feature
*feature
;
5121 if (!font
->GSUB_Table
)
5124 header
= font
->GSUB_Table
;
5126 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5129 TRACE("Script not found\n");
5132 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5135 TRACE("Language not found\n");
5138 feature
= GSUB_get_feature(header
, language
, "vrt2");
5140 feature
= GSUB_get_feature(header
, language
, "vert");
5143 TRACE("vrt2/vert feature not found\n");
5146 return GSUB_apply_feature(header
, feature
, glyph
);
5149 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5153 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5154 WCHAR wc
= (WCHAR
)glyph
;
5156 BOOL
*default_used_pointer
;
5159 default_used_pointer
= NULL
;
5160 default_used
= FALSE
;
5161 if (codepage_sets_default_used(font
->codepage
))
5162 default_used_pointer
= &default_used
;
5163 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5166 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5167 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5171 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5173 if (glyph
< 0x100) glyph
+= 0xf000;
5174 /* there is a number of old pre-Unicode "broken" TTFs, which
5175 do have symbols at U+00XX instead of U+f0XX */
5176 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5177 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5179 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5184 /*************************************************************
5185 * freetype_GetGlyphIndices
5187 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5189 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5192 BOOL got_default
= FALSE
;
5196 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5197 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5200 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5202 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5207 EnterCriticalSection( &freetype_cs
);
5209 for(i
= 0; i
< count
; i
++)
5211 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5216 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5218 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5219 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5224 get_text_metrics(physdev
->font
, &textm
);
5225 default_char
= textm
.tmDefaultChar
;
5229 pgi
[i
] = default_char
;
5232 LeaveCriticalSection( &freetype_cs
);
5236 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5238 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5239 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5242 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5244 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5245 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5248 static inline BYTE
get_max_level( UINT format
)
5252 case GGO_GRAY2_BITMAP
: return 4;
5253 case GGO_GRAY4_BITMAP
: return 16;
5254 case GGO_GRAY8_BITMAP
: return 64;
5259 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5261 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5262 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5265 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5266 FT_Face ft_face
= incoming_font
->ft_face
;
5267 GdiFont
*font
= incoming_font
;
5268 FT_UInt glyph_index
;
5269 DWORD width
, height
, pitch
, needed
= 0;
5270 FT_Bitmap ft_bitmap
;
5272 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5274 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5275 double widthRatio
= 1.0;
5276 FT_Matrix transMat
= identityMat
;
5277 FT_Matrix transMatUnrotated
;
5278 BOOL needsTransform
= FALSE
;
5279 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5280 UINT original_index
;
5282 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5283 buflen
, buf
, lpmat
);
5285 TRACE("font transform %f %f %f %f\n",
5286 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5287 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5289 if(format
& GGO_GLYPH_INDEX
) {
5290 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5291 original_index
= glyph
;
5292 format
&= ~GGO_GLYPH_INDEX
;
5294 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5295 ft_face
= font
->ft_face
;
5296 original_index
= glyph_index
;
5299 if(format
& GGO_UNHINTED
) {
5300 load_flags
|= FT_LOAD_NO_HINTING
;
5301 format
&= ~GGO_UNHINTED
;
5304 /* tategaki never appears to happen to lower glyph index */
5305 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5308 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5309 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5310 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5311 font
->gmsize
* sizeof(GM
*));
5313 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5314 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5316 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5317 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5318 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5319 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5320 return 1; /* FIXME */
5324 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5325 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5327 /* Scaling factor */
5332 get_text_metrics(font
, &tm
);
5334 widthRatio
= (double)font
->aveWidth
;
5335 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5338 widthRatio
= font
->scale_y
;
5340 /* Scaling transform */
5341 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5344 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5347 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5349 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5350 needsTransform
= TRUE
;
5353 /* Slant transform */
5354 if (font
->fake_italic
) {
5357 slantMat
.xx
= (1 << 16);
5358 slantMat
.xy
= ((1 << 16) >> 2);
5360 slantMat
.yy
= (1 << 16);
5361 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5362 needsTransform
= TRUE
;
5365 /* Rotation transform */
5366 transMatUnrotated
= transMat
;
5367 if(font
->orientation
&& !tategaki
) {
5368 FT_Matrix rotationMat
;
5370 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5371 pFT_Vector_Unit(&vecAngle
, angle
);
5372 rotationMat
.xx
= vecAngle
.x
;
5373 rotationMat
.xy
= -vecAngle
.y
;
5374 rotationMat
.yx
= -rotationMat
.xy
;
5375 rotationMat
.yy
= rotationMat
.xx
;
5377 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5378 needsTransform
= TRUE
;
5381 /* World transform */
5382 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5385 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5386 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5387 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5388 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5389 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5390 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5391 needsTransform
= TRUE
;
5394 /* Extra transformation specified by caller */
5395 if (!is_identity_MAT2(lpmat
))
5398 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5399 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5400 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5401 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5402 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5403 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5404 needsTransform
= TRUE
;
5407 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5408 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5409 format
== GGO_GRAY8_BITMAP
))
5411 load_flags
|= FT_LOAD_NO_BITMAP
;
5414 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5417 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5421 if(!needsTransform
) {
5422 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5423 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5424 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5426 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5427 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5428 ft_face
->glyph
->metrics
.height
) & -64;
5429 lpgm
->gmCellIncX
= adv
;
5430 lpgm
->gmCellIncY
= 0;
5437 for(xc
= 0; xc
< 2; xc
++) {
5438 for(yc
= 0; yc
< 2; yc
++) {
5439 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5440 xc
* ft_face
->glyph
->metrics
.width
);
5441 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5442 yc
* ft_face
->glyph
->metrics
.height
;
5443 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5444 pFT_Vector_Transform(&vec
, &transMat
);
5445 if(xc
== 0 && yc
== 0) {
5446 left
= right
= vec
.x
;
5447 top
= bottom
= vec
.y
;
5449 if(vec
.x
< left
) left
= vec
.x
;
5450 else if(vec
.x
> right
) right
= vec
.x
;
5451 if(vec
.y
< bottom
) bottom
= vec
.y
;
5452 else if(vec
.y
> top
) top
= vec
.y
;
5457 right
= (right
+ 63) & -64;
5458 bottom
= bottom
& -64;
5459 top
= (top
+ 63) & -64;
5461 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5462 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5464 pFT_Vector_Transform(&vec
, &transMat
);
5465 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5466 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5468 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5470 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5471 adv
= (vec
.x
+63) >> 6;
5475 bbx
= (right
- left
) >> 6;
5476 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5477 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5478 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5479 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5481 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5482 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5483 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5485 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5486 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5488 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5489 FONT_GM(font
,original_index
)->adv
= adv
;
5490 FONT_GM(font
,original_index
)->lsb
= lsb
;
5491 FONT_GM(font
,original_index
)->bbx
= bbx
;
5492 FONT_GM(font
,original_index
)->init
= TRUE
;
5495 if(format
== GGO_METRICS
)
5497 return 1; /* FIXME */
5500 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5501 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5503 TRACE("loaded a bitmap\n");
5509 width
= lpgm
->gmBlackBoxX
;
5510 height
= lpgm
->gmBlackBoxY
;
5511 pitch
= ((width
+ 31) >> 5) << 2;
5512 needed
= pitch
* height
;
5514 if(!buf
|| !buflen
) break;
5516 switch(ft_face
->glyph
->format
) {
5517 case ft_glyph_format_bitmap
:
5519 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5520 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5521 INT h
= ft_face
->glyph
->bitmap
.rows
;
5523 memcpy(dst
, src
, w
);
5524 src
+= ft_face
->glyph
->bitmap
.pitch
;
5530 case ft_glyph_format_outline
:
5531 ft_bitmap
.width
= width
;
5532 ft_bitmap
.rows
= height
;
5533 ft_bitmap
.pitch
= pitch
;
5534 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5535 ft_bitmap
.buffer
= buf
;
5538 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5540 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5542 /* Note: FreeType will only set 'black' bits for us. */
5543 memset(buf
, 0, needed
);
5544 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5548 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5553 case GGO_GRAY2_BITMAP
:
5554 case GGO_GRAY4_BITMAP
:
5555 case GGO_GRAY8_BITMAP
:
5556 case WINE_GGO_GRAY16_BITMAP
:
5558 unsigned int max_level
, row
, col
;
5561 width
= lpgm
->gmBlackBoxX
;
5562 height
= lpgm
->gmBlackBoxY
;
5563 pitch
= (width
+ 3) / 4 * 4;
5564 needed
= pitch
* height
;
5566 if(!buf
|| !buflen
) break;
5568 max_level
= get_max_level( format
);
5570 switch(ft_face
->glyph
->format
) {
5571 case ft_glyph_format_bitmap
:
5573 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5574 INT h
= ft_face
->glyph
->bitmap
.rows
;
5576 memset( buf
, 0, needed
);
5578 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5579 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5580 src
+= ft_face
->glyph
->bitmap
.pitch
;
5585 case ft_glyph_format_outline
:
5587 ft_bitmap
.width
= width
;
5588 ft_bitmap
.rows
= height
;
5589 ft_bitmap
.pitch
= pitch
;
5590 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5591 ft_bitmap
.buffer
= buf
;
5594 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5596 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5598 memset(ft_bitmap
.buffer
, 0, buflen
);
5600 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5602 if (max_level
!= 255)
5604 for (row
= 0, start
= buf
; row
< height
; row
++)
5606 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
5607 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
5615 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5621 case WINE_GGO_HRGB_BITMAP
:
5622 case WINE_GGO_HBGR_BITMAP
:
5623 case WINE_GGO_VRGB_BITMAP
:
5624 case WINE_GGO_VBGR_BITMAP
:
5625 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5627 switch (ft_face
->glyph
->format
)
5629 case FT_GLYPH_FORMAT_BITMAP
:
5634 width
= lpgm
->gmBlackBoxX
;
5635 height
= lpgm
->gmBlackBoxY
;
5637 needed
= pitch
* height
;
5639 if (!buf
|| !buflen
) break;
5641 memset(buf
, 0, buflen
);
5643 src
= ft_face
->glyph
->bitmap
.buffer
;
5644 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5646 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
5649 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5651 if ( src
[x
/ 8] & masks
[x
% 8] )
5652 ((unsigned int *)dst
)[x
] = ~0u;
5661 case FT_GLYPH_FORMAT_OUTLINE
:
5665 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
5666 INT x_shift
, y_shift
;
5668 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
5669 FT_Render_Mode render_mode
=
5670 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
5671 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
5673 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
5675 if ( render_mode
== FT_RENDER_MODE_LCD
)
5677 lpgm
->gmBlackBoxX
+= 2;
5678 lpgm
->gmptGlyphOrigin
.x
-= 1;
5682 lpgm
->gmBlackBoxY
+= 2;
5683 lpgm
->gmptGlyphOrigin
.y
+= 1;
5687 width
= lpgm
->gmBlackBoxX
;
5688 height
= lpgm
->gmBlackBoxY
;
5690 needed
= pitch
* height
;
5692 if (!buf
|| !buflen
) break;
5694 memset(buf
, 0, buflen
);
5696 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
5698 if ( needsTransform
)
5699 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
5701 if ( pFT_Library_SetLcdFilter
)
5702 pFT_Library_SetLcdFilter( library
, lcdfilter
);
5703 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
5705 src
= ft_face
->glyph
->bitmap
.buffer
;
5706 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
5707 src_width
= ft_face
->glyph
->bitmap
.width
;
5708 src_height
= ft_face
->glyph
->bitmap
.rows
;
5710 if ( render_mode
== FT_RENDER_MODE_LCD
)
5718 rgb_interval
= src_pitch
;
5723 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
5724 if ( x_shift
< 0 ) x_shift
= 0;
5725 if ( x_shift
+ (src_width
/ hmul
) > width
)
5726 x_shift
= width
- (src_width
/ hmul
);
5728 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
5729 if ( y_shift
< 0 ) y_shift
= 0;
5730 if ( y_shift
+ (src_height
/ vmul
) > height
)
5731 y_shift
= height
- (src_height
/ vmul
);
5733 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
5734 while ( src_height
)
5736 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
5740 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
5741 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5742 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
5743 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5747 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
5748 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
5749 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
5750 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
5753 src
+= src_pitch
* vmul
;
5762 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
5774 int contour
, point
= 0, first_pt
;
5775 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5776 TTPOLYGONHEADER
*pph
;
5778 DWORD pph_start
, cpfx
, type
;
5780 if(buflen
== 0) buf
= NULL
;
5782 if (needsTransform
&& buf
) {
5783 pFT_Outline_Transform(outline
, &transMat
);
5786 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5788 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5791 pph
->dwType
= TT_POLYGON_TYPE
;
5792 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5794 needed
+= sizeof(*pph
);
5796 while(point
<= outline
->contours
[contour
]) {
5797 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5798 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5799 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
5803 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5806 } while(point
<= outline
->contours
[contour
] &&
5807 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5808 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5809 /* At the end of a contour Windows adds the start point, but
5811 if(point
> outline
->contours
[contour
] &&
5812 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5814 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
5816 } else if(point
<= outline
->contours
[contour
] &&
5817 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5818 /* add closing pt for bezier */
5820 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5828 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5831 pph
->cb
= needed
- pph_start
;
5837 /* Convert the quadratic Beziers to cubic Beziers.
5838 The parametric eqn for a cubic Bezier is, from PLRM:
5839 r(t) = at^3 + bt^2 + ct + r0
5840 with the control points:
5845 A quadratic Bezier has the form:
5846 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5848 So equating powers of t leads to:
5849 r1 = 2/3 p1 + 1/3 p0
5850 r2 = 2/3 p1 + 1/3 p2
5851 and of course r0 = p0, r3 = p2
5854 int contour
, point
= 0, first_pt
;
5855 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
5856 TTPOLYGONHEADER
*pph
;
5858 DWORD pph_start
, cpfx
, type
;
5859 FT_Vector cubic_control
[4];
5860 if(buflen
== 0) buf
= NULL
;
5862 if (needsTransform
&& buf
) {
5863 pFT_Outline_Transform(outline
, &transMat
);
5866 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
5868 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
5871 pph
->dwType
= TT_POLYGON_TYPE
;
5872 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
5874 needed
+= sizeof(*pph
);
5876 while(point
<= outline
->contours
[contour
]) {
5877 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
5878 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
5879 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
5882 if(type
== TT_PRIM_LINE
) {
5884 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
5888 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5891 /* FIXME: Possible optimization in endpoint calculation
5892 if there are two consecutive curves */
5893 cubic_control
[0] = outline
->points
[point
-1];
5894 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
5895 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
5896 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
5897 cubic_control
[0].x
>>= 1;
5898 cubic_control
[0].y
>>= 1;
5900 if(point
+1 > outline
->contours
[contour
])
5901 cubic_control
[3] = outline
->points
[first_pt
];
5903 cubic_control
[3] = outline
->points
[point
+1];
5904 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
5905 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
5906 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
5907 cubic_control
[3].x
>>= 1;
5908 cubic_control
[3].y
>>= 1;
5911 /* r1 = 1/3 p0 + 2/3 p1
5912 r2 = 1/3 p2 + 2/3 p1 */
5913 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
5914 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
5915 cubic_control
[2] = cubic_control
[1];
5916 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
5917 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
5918 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
5919 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
5921 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
5922 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
5923 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
5928 } while(point
<= outline
->contours
[contour
] &&
5929 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
5930 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
5931 /* At the end of a contour Windows adds the start point,
5932 but only for Beziers and we've already done that.
5934 if(point
<= outline
->contours
[contour
] &&
5935 outline
->tags
[point
] & FT_Curve_Tag_On
) {
5936 /* This is the closing pt of a bezier, but we've already
5937 added it, so just inc point and carry on */
5944 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
5947 pph
->cb
= needed
- pph_start
;
5953 FIXME("Unsupported format %d\n", format
);
5959 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
5961 FT_Face ft_face
= font
->ft_face
;
5962 FT_WinFNT_HeaderRec winfnt_header
;
5963 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
5964 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
5965 font
->potm
->otmSize
= size
;
5967 #define TM font->potm->otmTextMetrics
5968 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
5970 TM
.tmHeight
= winfnt_header
.pixel_height
;
5971 TM
.tmAscent
= winfnt_header
.ascent
;
5972 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
5973 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
5974 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
5975 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
5976 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
5977 TM
.tmWeight
= winfnt_header
.weight
;
5979 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
5980 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
5981 TM
.tmFirstChar
= winfnt_header
.first_char
;
5982 TM
.tmLastChar
= winfnt_header
.last_char
;
5983 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
5984 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
5985 TM
.tmItalic
= winfnt_header
.italic
;
5986 TM
.tmUnderlined
= font
->underline
;
5987 TM
.tmStruckOut
= font
->strikeout
;
5988 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
5989 TM
.tmCharSet
= winfnt_header
.charset
;
5993 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
5994 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
5995 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
5996 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
5997 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
5998 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
5999 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6000 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6002 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6003 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6005 TM
.tmLastChar
= 255;
6006 TM
.tmDefaultChar
= 32;
6007 TM
.tmBreakChar
= 32;
6008 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6009 TM
.tmUnderlined
= font
->underline
;
6010 TM
.tmStruckOut
= font
->strikeout
;
6011 /* NB inverted meaning of TMPF_FIXED_PITCH */
6012 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6013 TM
.tmCharSet
= font
->charset
;
6021 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6023 double scale_x
, scale_y
;
6027 scale_x
= (double)font
->aveWidth
;
6028 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6031 scale_x
= font
->scale_y
;
6033 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6034 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6036 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6037 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6039 SCALE_Y(ptm
->tmHeight
);
6040 SCALE_Y(ptm
->tmAscent
);
6041 SCALE_Y(ptm
->tmDescent
);
6042 SCALE_Y(ptm
->tmInternalLeading
);
6043 SCALE_Y(ptm
->tmExternalLeading
);
6044 SCALE_Y(ptm
->tmOverhang
);
6046 SCALE_X(ptm
->tmAveCharWidth
);
6047 SCALE_X(ptm
->tmMaxCharWidth
);
6053 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6055 double scale_x
, scale_y
;
6059 scale_x
= (double)font
->aveWidth
;
6060 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6063 scale_x
= font
->scale_y
;
6065 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6066 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6068 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6070 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6071 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6073 SCALE_Y(potm
->otmAscent
);
6074 SCALE_Y(potm
->otmDescent
);
6075 SCALE_Y(potm
->otmLineGap
);
6076 SCALE_Y(potm
->otmsCapEmHeight
);
6077 SCALE_Y(potm
->otmsXHeight
);
6078 SCALE_Y(potm
->otmrcFontBox
.top
);
6079 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6080 SCALE_X(potm
->otmrcFontBox
.left
);
6081 SCALE_X(potm
->otmrcFontBox
.right
);
6082 SCALE_Y(potm
->otmMacAscent
);
6083 SCALE_Y(potm
->otmMacDescent
);
6084 SCALE_Y(potm
->otmMacLineGap
);
6085 SCALE_X(potm
->otmptSubscriptSize
.x
);
6086 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6087 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6088 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6089 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6090 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6091 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6092 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6093 SCALE_Y(potm
->otmsStrikeoutSize
);
6094 SCALE_Y(potm
->otmsStrikeoutPosition
);
6095 SCALE_Y(potm
->otmsUnderscoreSize
);
6096 SCALE_Y(potm
->otmsUnderscorePosition
);
6102 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6106 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6108 /* Make sure that the font has sane width/height ratio */
6111 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6113 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6118 *ptm
= font
->potm
->otmTextMetrics
;
6119 scale_font_metrics(font
, ptm
);
6123 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6127 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6129 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6135 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6138 FT_Face ft_face
= font
->ft_face
;
6139 UINT needed
, lenfam
, lensty
;
6141 TT_HoriHeader
*pHori
;
6142 TT_Postscript
*pPost
;
6143 FT_Fixed x_scale
, y_scale
;
6144 WCHAR
*family_nameW
, *style_nameW
;
6145 static const WCHAR spaceW
[] = {' ', '\0'};
6147 INT ascent
, descent
;
6149 TRACE("font=%p\n", font
);
6151 if(!FT_IS_SCALABLE(ft_face
))
6154 needed
= sizeof(*font
->potm
);
6156 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6157 family_nameW
= strdupW(font
->name
);
6159 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6161 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6162 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6163 style_nameW
, lensty
/sizeof(WCHAR
));
6165 /* These names should be read from the TT name table */
6167 /* length of otmpFamilyName */
6170 /* length of otmpFaceName */
6171 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6172 needed
+= lenfam
; /* just the family name */
6174 needed
+= lenfam
+ lensty
; /* family + " " + style */
6177 /* length of otmpStyleName */
6180 /* length of otmpFullName */
6181 needed
+= lenfam
+ lensty
;
6184 x_scale
= ft_face
->size
->metrics
.x_scale
;
6185 y_scale
= ft_face
->size
->metrics
.y_scale
;
6187 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6189 FIXME("Can't find OS/2 table - not TT font?\n");
6193 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6195 FIXME("Can't find HHEA table - not TT font?\n");
6199 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6201 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",
6202 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6203 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6204 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6205 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6206 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6208 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6209 font
->potm
->otmSize
= needed
;
6211 #define TM font->potm->otmTextMetrics
6213 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6214 ascent
= pHori
->Ascender
;
6215 descent
= -pHori
->Descender
;
6217 ascent
= pOS2
->usWinAscent
;
6218 descent
= pOS2
->usWinDescent
;
6222 TM
.tmAscent
= font
->yMax
;
6223 TM
.tmDescent
= -font
->yMin
;
6224 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6226 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6227 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6228 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6229 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6232 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6235 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6237 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6238 ((ascent
+ descent
) -
6239 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6241 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6242 if (TM
.tmAveCharWidth
== 0) {
6243 TM
.tmAveCharWidth
= 1;
6245 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6246 TM
.tmWeight
= FW_REGULAR
;
6247 if (font
->fake_bold
)
6248 TM
.tmWeight
= FW_BOLD
;
6251 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6253 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6254 TM
.tmWeight
= pOS2
->usWeightClass
;
6256 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6257 TM
.tmWeight
= pOS2
->usWeightClass
;
6260 TM
.tmDigitizedAspectX
= 300;
6261 TM
.tmDigitizedAspectY
= 300;
6262 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6263 * symbol range to 0 - f0ff
6266 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6271 case 1257: /* Baltic */
6272 TM
.tmLastChar
= 0xf8fd;
6275 TM
.tmLastChar
= 0xf0ff;
6277 TM
.tmBreakChar
= 0x20;
6278 TM
.tmDefaultChar
= 0x1f;
6282 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6283 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6285 if(pOS2
->usFirstCharIndex
<= 1)
6286 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6287 else if (pOS2
->usFirstCharIndex
> 0xff)
6288 TM
.tmBreakChar
= 0x20;
6290 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6291 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6293 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6294 TM
.tmUnderlined
= font
->underline
;
6295 TM
.tmStruckOut
= font
->strikeout
;
6297 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6298 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6299 (pOS2
->version
== 0xFFFFU
||
6300 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6301 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6303 TM
.tmPitchAndFamily
= 0;
6305 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6307 case PAN_FAMILY_SCRIPT
:
6308 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6311 case PAN_FAMILY_DECORATIVE
:
6312 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6317 case PAN_FAMILY_TEXT_DISPLAY
:
6318 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6319 /* which is clearly not what the panose spec says. */
6321 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6322 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6323 TM
.tmPitchAndFamily
= FF_MODERN
;
6326 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6331 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6334 case PAN_SERIF_COVE
:
6335 case PAN_SERIF_OBTUSE_COVE
:
6336 case PAN_SERIF_SQUARE_COVE
:
6337 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6338 case PAN_SERIF_SQUARE
:
6339 case PAN_SERIF_THIN
:
6340 case PAN_SERIF_BONE
:
6341 case PAN_SERIF_EXAGGERATED
:
6342 case PAN_SERIF_TRIANGLE
:
6343 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6346 case PAN_SERIF_NORMAL_SANS
:
6347 case PAN_SERIF_OBTUSE_SANS
:
6348 case PAN_SERIF_PERP_SANS
:
6349 case PAN_SERIF_FLARED
:
6350 case PAN_SERIF_ROUNDED
:
6351 TM
.tmPitchAndFamily
|= FF_SWISS
;
6358 if(FT_IS_SCALABLE(ft_face
))
6359 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6361 if(FT_IS_SFNT(ft_face
))
6363 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6364 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6366 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6369 TM
.tmCharSet
= font
->charset
;
6371 font
->potm
->otmFiller
= 0;
6372 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6373 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6374 font
->potm
->otmfsType
= pOS2
->fsType
;
6375 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6376 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6377 font
->potm
->otmItalicAngle
= 0; /* POST table */
6378 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6379 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6380 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6381 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6382 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6383 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6384 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6385 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6386 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6387 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6388 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6389 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6390 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6391 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6392 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6393 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6394 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6395 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6396 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6397 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6398 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6399 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6400 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6401 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6403 font
->potm
->otmsUnderscoreSize
= 0;
6404 font
->potm
->otmsUnderscorePosition
= 0;
6406 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6407 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6411 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6412 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6413 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6414 strcpyW((WCHAR
*)cp
, family_nameW
);
6416 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6417 strcpyW((WCHAR
*)cp
, style_nameW
);
6419 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6420 strcpyW((WCHAR
*)cp
, family_nameW
);
6421 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6422 strcatW((WCHAR
*)cp
, spaceW
);
6423 strcatW((WCHAR
*)cp
, style_nameW
);
6424 cp
+= lenfam
+ lensty
;
6427 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6428 strcpyW((WCHAR
*)cp
, family_nameW
);
6429 strcatW((WCHAR
*)cp
, spaceW
);
6430 strcatW((WCHAR
*)cp
, style_nameW
);
6434 HeapFree(GetProcessHeap(), 0, style_nameW
);
6435 HeapFree(GetProcessHeap(), 0, family_nameW
);
6439 /*************************************************************
6440 * freetype_GetGlyphOutline
6442 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6443 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6445 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6450 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6451 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6455 EnterCriticalSection( &freetype_cs
);
6456 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6457 LeaveCriticalSection( &freetype_cs
);
6461 /*************************************************************
6462 * freetype_GetTextMetrics
6464 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6466 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6471 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6472 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6476 EnterCriticalSection( &freetype_cs
);
6477 ret
= get_text_metrics( physdev
->font
, metrics
);
6478 LeaveCriticalSection( &freetype_cs
);
6482 /*************************************************************
6483 * freetype_GetOutlineTextMetrics
6485 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6487 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6492 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6493 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6496 TRACE("font=%p\n", physdev
->font
);
6498 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6501 EnterCriticalSection( &freetype_cs
);
6503 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6505 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6507 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6508 scale_outline_font_metrics(physdev
->font
, potm
);
6510 ret
= physdev
->font
->potm
->otmSize
;
6512 LeaveCriticalSection( &freetype_cs
);
6516 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6518 HFONTLIST
*hfontlist
;
6519 child
->font
= alloc_font();
6520 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6521 if(!child
->font
->ft_face
)
6523 free_font(child
->font
);
6528 child
->font
->font_desc
= font
->font_desc
;
6529 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6530 child
->font
->orientation
= font
->orientation
;
6531 child
->font
->scale_y
= font
->scale_y
;
6532 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6533 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6534 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6535 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6536 child
->font
->base_font
= font
;
6537 list_add_head(&child_font_list
, &child
->font
->entry
);
6538 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6542 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6545 CHILD_FONT
*child_font
;
6548 font
= font
->base_font
;
6550 *linked_font
= font
;
6552 if((*glyph
= get_glyph_index(font
, c
)))
6554 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6558 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6560 if(!child_font
->font
)
6561 if(!load_child_font(font
, child_font
))
6564 if(!child_font
->font
->ft_face
)
6566 g
= get_glyph_index(child_font
->font
, c
);
6567 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6571 *linked_font
= child_font
->font
;
6578 /*************************************************************
6579 * freetype_GetCharWidth
6581 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6583 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6586 FT_UInt glyph_index
;
6587 GdiFont
*linked_font
;
6588 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6592 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6593 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6596 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6599 EnterCriticalSection( &freetype_cs
);
6600 for(c
= firstChar
; c
<= lastChar
; c
++) {
6601 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6602 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6603 &gm
, 0, NULL
, &identity
);
6604 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
6606 LeaveCriticalSection( &freetype_cs
);
6610 /*************************************************************
6611 * freetype_GetCharABCWidths
6613 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
6615 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6618 FT_UInt glyph_index
;
6619 GdiFont
*linked_font
;
6620 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6624 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
6625 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
6628 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6631 EnterCriticalSection( &freetype_cs
);
6633 for(c
= firstChar
; c
<= lastChar
; c
++) {
6634 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6635 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6636 &gm
, 0, NULL
, &identity
);
6637 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
6638 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
6639 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
6640 FONT_GM(linked_font
,glyph_index
)->bbx
;
6642 LeaveCriticalSection( &freetype_cs
);
6646 /*************************************************************
6647 * freetype_GetCharABCWidthsI
6649 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
6651 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6654 FT_UInt glyph_index
;
6655 GdiFont
*linked_font
;
6656 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6660 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
6661 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
6664 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
6668 EnterCriticalSection( &freetype_cs
);
6670 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
6672 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
6673 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6674 &gm
, 0, NULL
, &identity
);
6675 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
6676 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
6677 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
6678 - FONT_GM(linked_font
,c
)->bbx
;
6681 for(c
= 0; c
< count
; c
++) {
6682 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
6683 &gm
, 0, NULL
, &identity
);
6684 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
6685 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
6686 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
6687 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
6690 LeaveCriticalSection( &freetype_cs
);
6694 /*************************************************************
6695 * freetype_GetTextExtentExPoint
6697 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
6698 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6700 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6705 FT_UInt glyph_index
;
6706 GdiFont
*linked_font
;
6707 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6711 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
6712 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
6715 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
6718 EnterCriticalSection( &freetype_cs
);
6721 get_text_metrics( physdev
->font
, &tm
);
6722 size
->cy
= tm
.tmHeight
;
6724 for(idx
= 0; idx
< count
; idx
++) {
6725 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
6726 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6727 &gm
, 0, NULL
, &identity
);
6728 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
6730 if (! pnfit
|| ext
<= max_ext
) {
6740 LeaveCriticalSection( &freetype_cs
);
6741 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6745 /*************************************************************
6746 * freetype_GetTextExtentExPointI
6748 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
6749 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
6751 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6756 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6760 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
6761 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
6764 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
6767 EnterCriticalSection( &freetype_cs
);
6770 get_text_metrics(physdev
->font
, &tm
);
6771 size
->cy
= tm
.tmHeight
;
6773 for(idx
= 0; idx
< count
; idx
++) {
6774 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
6775 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
6777 if (! pnfit
|| ext
<= max_ext
) {
6787 LeaveCriticalSection( &freetype_cs
);
6788 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
6792 /*************************************************************
6793 * freetype_GetFontData
6795 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
6797 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6801 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
6802 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
6805 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6806 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
6807 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
6809 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
6812 /*************************************************************
6813 * freetype_GetTextFace
6815 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
6818 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6822 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
6823 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
6826 n
= strlenW(physdev
->font
->name
) + 1;
6829 lstrcpynW(str
, physdev
->font
->name
, count
);
6835 /*************************************************************
6836 * freetype_GetTextCharsetInfo
6838 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
6840 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6844 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
6845 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
6847 if (fs
) *fs
= physdev
->font
->fs
;
6848 return physdev
->font
->charset
;
6851 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
6853 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
6854 struct list
*first_hfont
;
6858 EnterCriticalSection( &freetype_cs
);
6859 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
6860 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
6861 if(font
== linked_font
)
6862 *new_hfont
= dc
->hFont
;
6865 first_hfont
= list_head(&linked_font
->hfontlist
);
6866 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
6868 LeaveCriticalSection( &freetype_cs
);
6872 /* Retrieve a list of supported Unicode ranges for a given font.
6873 * Can be called with NULL gs to calculate the buffer size. Returns
6874 * the number of ranges found.
6876 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
6878 DWORD num_ranges
= 0;
6880 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
6883 FT_ULong char_code
, char_code_prev
;
6886 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
6888 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6889 face
->num_glyphs
, glyph_code
, char_code
);
6891 if (!glyph_code
) return 0;
6895 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
6896 gs
->ranges
[0].cGlyphs
= 0;
6897 gs
->cGlyphsSupported
= 0;
6903 if (char_code
< char_code_prev
)
6905 ERR("expected increasing char code from FT_Get_Next_Char\n");
6908 if (char_code
- char_code_prev
> 1)
6913 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
6914 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
6915 gs
->cGlyphsSupported
++;
6920 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
6921 gs
->cGlyphsSupported
++;
6923 char_code_prev
= char_code
;
6924 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
6928 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
6933 /*************************************************************
6934 * freetype_GetFontUnicodeRanges
6936 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
6938 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6939 DWORD size
, num_ranges
;
6943 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
6944 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
6947 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
6948 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
6951 glyphset
->cbThis
= size
;
6952 glyphset
->cRanges
= num_ranges
;
6953 glyphset
->flAccel
= 0;
6958 /*************************************************************
6959 * freetype_FontIsLinked
6961 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
6963 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6968 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
6969 return dev
->funcs
->pFontIsLinked( dev
);
6973 EnterCriticalSection( &freetype_cs
);
6974 ret
= !list_empty(&physdev
->font
->child_fonts
);
6975 LeaveCriticalSection( &freetype_cs
);
6979 static BOOL
is_hinting_enabled(void)
6981 /* Use the >= 2.2.0 function if available */
6982 if(pFT_Get_TrueType_Engine_Type
)
6984 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
6985 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
6987 #ifdef FT_DRIVER_HAS_HINTER
6992 /* otherwise if we've been compiled with < 2.2.0 headers
6993 use the internal macro */
6994 mod
= pFT_Get_Module(library
, "truetype");
6995 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
7003 static BOOL
is_subpixel_rendering_enabled( void )
7005 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7006 return pFT_Library_SetLcdFilter
&&
7007 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
7013 /*************************************************************************
7014 * GetRasterizerCaps (GDI32.@)
7016 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7018 static int hinting
= -1;
7019 static int subpixel
= -1;
7023 hinting
= is_hinting_enabled();
7024 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
7027 if ( subpixel
== -1 )
7029 subpixel
= is_subpixel_rendering_enabled();
7030 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
7033 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7034 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
7036 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
7037 lprs
->nLanguageID
= 0;
7041 /*************************************************************
7042 * freetype_GdiRealizationInfo
7044 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7046 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7047 realization_info_t
*info
= ptr
;
7051 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7052 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7055 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7058 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7061 info
->cache_num
= physdev
->font
->cache_num
;
7062 info
->unknown2
= -1;
7066 /*************************************************************************
7067 * Kerning support for TrueType fonts
7069 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7071 struct TT_kern_table
7077 struct TT_kern_subtable
7086 USHORT horizontal
: 1;
7088 USHORT cross_stream
: 1;
7089 USHORT override
: 1;
7090 USHORT reserved1
: 4;
7096 struct TT_format0_kern_subtable
7100 USHORT entrySelector
;
7111 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7112 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7113 const USHORT
*glyph_to_char
,
7114 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7117 const struct TT_kern_pair
*tt_kern_pair
;
7119 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7121 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7123 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7124 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7125 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7127 if (!kern_pair
|| !cPairs
)
7130 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7132 nPairs
= min(nPairs
, cPairs
);
7134 for (i
= 0; i
< nPairs
; i
++)
7136 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7137 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7138 /* this algorithm appears to better match what Windows does */
7139 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7140 if (kern_pair
->iKernAmount
< 0)
7142 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7143 kern_pair
->iKernAmount
-= font
->ppem
;
7145 else if (kern_pair
->iKernAmount
> 0)
7147 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7148 kern_pair
->iKernAmount
+= font
->ppem
;
7150 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7152 TRACE("left %u right %u value %d\n",
7153 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7157 TRACE("copied %u entries\n", nPairs
);
7161 /*************************************************************
7162 * freetype_GetKerningPairs
7164 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7168 const struct TT_kern_table
*tt_kern_table
;
7169 const struct TT_kern_subtable
*tt_kern_subtable
;
7171 USHORT
*glyph_to_char
;
7173 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7175 if (!(font
= physdev
->font
))
7177 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7178 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7182 EnterCriticalSection( &freetype_cs
);
7183 if (font
->total_kern_pairs
!= (DWORD
)-1)
7185 if (cPairs
&& kern_pair
)
7187 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7188 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7190 else cPairs
= font
->total_kern_pairs
;
7192 LeaveCriticalSection( &freetype_cs
);
7196 font
->total_kern_pairs
= 0;
7198 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7200 if (length
== GDI_ERROR
)
7202 TRACE("no kerning data in the font\n");
7203 LeaveCriticalSection( &freetype_cs
);
7207 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7210 WARN("Out of memory\n");
7211 LeaveCriticalSection( &freetype_cs
);
7215 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7217 /* build a glyph index to char code map */
7218 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7221 WARN("Out of memory allocating a glyph index to char code map\n");
7222 HeapFree(GetProcessHeap(), 0, buf
);
7223 LeaveCriticalSection( &freetype_cs
);
7227 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7233 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7235 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7236 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7240 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7242 /* FIXME: This doesn't match what Windows does: it does some fancy
7243 * things with duplicate glyph index to char code mappings, while
7244 * we just avoid overriding existing entries.
7246 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7247 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7249 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7256 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7257 for (n
= 0; n
<= 65535; n
++)
7258 glyph_to_char
[n
] = (USHORT
)n
;
7261 tt_kern_table
= buf
;
7262 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7263 TRACE("version %u, nTables %u\n",
7264 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7266 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7268 for (i
= 0; i
< nTables
; i
++)
7270 struct TT_kern_subtable tt_kern_subtable_copy
;
7272 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7273 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7274 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7276 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7277 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7278 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7280 /* According to the TrueType specification this is the only format
7281 * that will be properly interpreted by Windows and OS/2
7283 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7285 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7287 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7288 glyph_to_char
, NULL
, 0);
7289 font
->total_kern_pairs
+= new_chunk
;
7291 if (!font
->kern_pairs
)
7292 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7293 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7295 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7296 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7298 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7299 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7302 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7304 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7307 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7308 HeapFree(GetProcessHeap(), 0, buf
);
7310 if (cPairs
&& kern_pair
)
7312 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7313 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7315 else cPairs
= font
->total_kern_pairs
;
7317 LeaveCriticalSection( &freetype_cs
);
7321 static const struct gdi_dc_funcs freetype_funcs
=
7323 NULL
, /* pAbortDoc */
7324 NULL
, /* pAbortPath */
7325 NULL
, /* pAlphaBlend */
7326 NULL
, /* pAngleArc */
7329 NULL
, /* pBeginPath */
7330 NULL
, /* pBlendImage */
7331 NULL
, /* pChoosePixelFormat */
7333 NULL
, /* pCloseFigure */
7334 NULL
, /* pCopyBitmap */
7335 NULL
, /* pCreateBitmap */
7336 NULL
, /* pCreateCompatibleDC */
7337 freetype_CreateDC
, /* pCreateDC */
7338 NULL
, /* pDeleteBitmap */
7339 freetype_DeleteDC
, /* pDeleteDC */
7340 NULL
, /* pDeleteObject */
7341 NULL
, /* pDescribePixelFormat */
7342 NULL
, /* pDeviceCapabilities */
7343 NULL
, /* pEllipse */
7345 NULL
, /* pEndPage */
7346 NULL
, /* pEndPath */
7347 freetype_EnumFonts
, /* pEnumFonts */
7348 NULL
, /* pEnumICMProfiles */
7349 NULL
, /* pExcludeClipRect */
7350 NULL
, /* pExtDeviceMode */
7351 NULL
, /* pExtEscape */
7352 NULL
, /* pExtFloodFill */
7353 NULL
, /* pExtSelectClipRgn */
7354 NULL
, /* pExtTextOut */
7355 NULL
, /* pFillPath */
7356 NULL
, /* pFillRgn */
7357 NULL
, /* pFlattenPath */
7358 freetype_FontIsLinked
, /* pFontIsLinked */
7359 NULL
, /* pFrameRgn */
7360 NULL
, /* pGdiComment */
7361 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7362 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7363 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7364 freetype_GetCharWidth
, /* pGetCharWidth */
7365 NULL
, /* pGetDeviceCaps */
7366 NULL
, /* pGetDeviceGammaRamp */
7367 freetype_GetFontData
, /* pGetFontData */
7368 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7369 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7370 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7371 NULL
, /* pGetICMProfile */
7372 NULL
, /* pGetImage */
7373 freetype_GetKerningPairs
, /* pGetKerningPairs */
7374 NULL
, /* pGetNearestColor */
7375 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7376 NULL
, /* pGetPixel */
7377 NULL
, /* pGetPixelFormat */
7378 NULL
, /* pGetSystemPaletteEntries */
7379 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7380 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7381 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7382 freetype_GetTextFace
, /* pGetTextFace */
7383 freetype_GetTextMetrics
, /* pGetTextMetrics */
7384 NULL
, /* pGradientFill */
7385 NULL
, /* pIntersectClipRect */
7386 NULL
, /* pInvertRgn */
7388 NULL
, /* pModifyWorldTransform */
7390 NULL
, /* pOffsetClipRgn */
7391 NULL
, /* pOffsetViewportOrg */
7392 NULL
, /* pOffsetWindowOrg */
7393 NULL
, /* pPaintRgn */
7396 NULL
, /* pPolyBezier */
7397 NULL
, /* pPolyBezierTo */
7398 NULL
, /* pPolyDraw */
7399 NULL
, /* pPolyPolygon */
7400 NULL
, /* pPolyPolyline */
7401 NULL
, /* pPolygon */
7402 NULL
, /* pPolyline */
7403 NULL
, /* pPolylineTo */
7404 NULL
, /* pPutImage */
7405 NULL
, /* pRealizeDefaultPalette */
7406 NULL
, /* pRealizePalette */
7407 NULL
, /* pRectangle */
7408 NULL
, /* pResetDC */
7409 NULL
, /* pRestoreDC */
7410 NULL
, /* pRoundRect */
7412 NULL
, /* pScaleViewportExt */
7413 NULL
, /* pScaleWindowExt */
7414 NULL
, /* pSelectBitmap */
7415 NULL
, /* pSelectBrush */
7416 NULL
, /* pSelectClipPath */
7417 freetype_SelectFont
, /* pSelectFont */
7418 NULL
, /* pSelectPalette */
7419 NULL
, /* pSelectPen */
7420 NULL
, /* pSetArcDirection */
7421 NULL
, /* pSetBkColor */
7422 NULL
, /* pSetBkMode */
7423 NULL
, /* pSetDCBrushColor */
7424 NULL
, /* pSetDCPenColor */
7425 NULL
, /* pSetDIBColorTable */
7426 NULL
, /* pSetDIBitsToDevice */
7427 NULL
, /* pSetDeviceClipping */
7428 NULL
, /* pSetDeviceGammaRamp */
7429 NULL
, /* pSetLayout */
7430 NULL
, /* pSetMapMode */
7431 NULL
, /* pSetMapperFlags */
7432 NULL
, /* pSetPixel */
7433 NULL
, /* pSetPixelFormat */
7434 NULL
, /* pSetPolyFillMode */
7435 NULL
, /* pSetROP2 */
7436 NULL
, /* pSetRelAbs */
7437 NULL
, /* pSetStretchBltMode */
7438 NULL
, /* pSetTextAlign */
7439 NULL
, /* pSetTextCharacterExtra */
7440 NULL
, /* pSetTextColor */
7441 NULL
, /* pSetTextJustification */
7442 NULL
, /* pSetViewportExt */
7443 NULL
, /* pSetViewportOrg */
7444 NULL
, /* pSetWindowExt */
7445 NULL
, /* pSetWindowOrg */
7446 NULL
, /* pSetWorldTransform */
7447 NULL
, /* pStartDoc */
7448 NULL
, /* pStartPage */
7449 NULL
, /* pStretchBlt */
7450 NULL
, /* pStretchDIBits */
7451 NULL
, /* pStrokeAndFillPath */
7452 NULL
, /* pStrokePath */
7453 NULL
, /* pSwapBuffers */
7454 NULL
, /* pUnrealizePalette */
7455 NULL
, /* pWidenPath */
7456 /* OpenGL not supported */
7459 #else /* HAVE_FREETYPE */
7461 /*************************************************************************/
7463 BOOL
WineEngInit(void)
7467 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7472 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7474 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7478 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7480 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7484 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7486 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7490 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7495 /*************************************************************************
7496 * GetRasterizerCaps (GDI32.@)
7498 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7500 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7502 lprs
->nLanguageID
= 0;
7506 #endif /* HAVE_FREETYPE */