2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font
);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType
;
144 static FT_Library library
= 0;
151 static FT_Version_t FT_Version
;
152 static DWORD FT_SimpleVersion
;
154 static void *ft_handle
= NULL
;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face
);
158 MAKE_FUNCPTR(FT_Get_Char_Index
);
159 MAKE_FUNCPTR(FT_Get_First_Char
);
160 MAKE_FUNCPTR(FT_Get_Module
);
161 MAKE_FUNCPTR(FT_Get_Next_Char
);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
166 MAKE_FUNCPTR(FT_Init_FreeType
);
167 MAKE_FUNCPTR(FT_Library_Version
);
168 MAKE_FUNCPTR(FT_Load_Glyph
);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
170 MAKE_FUNCPTR(FT_Matrix_Multiply
);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix
);
176 MAKE_FUNCPTR(FT_New_Face
);
177 MAKE_FUNCPTR(FT_New_Memory_Face
);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
179 MAKE_FUNCPTR(FT_Outline_Transform
);
180 MAKE_FUNCPTR(FT_Outline_Translate
);
181 MAKE_FUNCPTR(FT_Render_Glyph
);
182 MAKE_FUNCPTR(FT_Select_Charmap
);
183 MAKE_FUNCPTR(FT_Set_Charmap
);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
185 MAKE_FUNCPTR(FT_Vector_Transform
);
186 MAKE_FUNCPTR(FT_Vector_Unit
);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent
);
195 MAKE_FUNCPTR(FcFontList
);
196 MAKE_FUNCPTR(FcFontSetDestroy
);
197 MAKE_FUNCPTR(FcInit
);
198 MAKE_FUNCPTR(FcObjectSetAdd
);
199 MAKE_FUNCPTR(FcObjectSetCreate
);
200 MAKE_FUNCPTR(FcObjectSetDestroy
);
201 MAKE_FUNCPTR(FcPatternCreate
);
202 MAKE_FUNCPTR(FcPatternDestroy
);
203 MAKE_FUNCPTR(FcPatternGetBool
);
204 MAKE_FUNCPTR(FcPatternGetString
);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading
;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height
, width
;
249 FT_Pos size
, x_ppem
, y_ppem
;
255 NEWTEXTMETRICEXW ntm
;
259 typedef struct tagFace
{
265 DWORD font_data_size
;
269 FT_Fixed font_version
;
272 Bitmap_Size size
; /* set if face is a bitmap */
273 BOOL external
; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily
*family
;
275 /* Cached data for Enum */
276 struct enum_data
*cached_enum_data
;
279 typedef struct tagFamily
{
284 struct list
*replacement
;
289 INT adv
; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST
{
322 struct list hfontlist
;
323 OUTLINETEXTMETRICW
*potm
;
324 DWORD total_kern_pairs
;
325 KERNINGPAIR
*kern_pairs
;
326 struct list child_fonts
;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping
*mapping
;
353 const WCHAR
*font_name
;
358 struct enum_charset_element
{
361 WCHAR name
[LF_FACESIZE
];
364 struct enum_charset_list
{
366 struct enum_charset_element element
[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
373 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list
= LIST_INIT(child_font_list
);
376 static struct list system_links
= LIST_INIT(system_links
);
378 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
380 static struct list font_list
= LIST_INIT(font_list
);
382 struct freetype_physdev
384 struct gdi_physdev dev
;
388 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
390 return (struct freetype_physdev
*)dev
;
393 static const struct gdi_dc_funcs freetype_funcs
;
395 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR
* const SystemFontValues
[] = {
422 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial
[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR
*default_serif_list
[] =
450 bitstream_vera_serif
,
454 static const WCHAR
*default_fixed_list
[] =
458 bitstream_vera_sans_mono
,
462 static const WCHAR
*default_sans_list
[] =
475 typedef struct tagFontSubst
{
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
487 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
488 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_vertical_value
[] = {'V','e','r','t','i','c','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 const struct list
*get_face_list_from_family(const Family
*family
)
894 if (!list_empty(&family
->faces
))
895 return &family
->faces
;
897 return family
->replacement
;
900 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
905 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
906 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
908 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
909 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
911 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
913 const struct list
*face_list
;
914 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
916 face_list
= get_face_list_from_family(family
);
917 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
921 file
= strrchr(face
->file
, '/');
926 if(!strcasecmp(file
, file_nameA
))
928 HeapFree(GetProcessHeap(), 0, file_nameA
);
933 HeapFree(GetProcessHeap(), 0, file_nameA
);
937 static Family
*find_family_from_name(const WCHAR
*name
)
941 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
943 if(!strcmpiW(family
->FamilyName
, name
))
950 static Family
*find_family_from_any_name(const WCHAR
*name
)
954 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
956 if(!strcmpiW(family
->FamilyName
, name
))
958 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
965 static void DumpSubstList(void)
969 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
971 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
972 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
973 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
975 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
976 debugstr_w(psub
->to
.name
));
981 static LPWSTR
strdupW(LPCWSTR p
)
984 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
985 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
990 static LPSTR
strdupA(LPCSTR p
)
993 DWORD len
= (strlen(p
) + 1);
994 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
999 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1004 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1006 if(!strcmpiW(element
->from
.name
, from_name
) &&
1007 (element
->from
.charset
== from_charset
||
1008 element
->from
.charset
== -1))
1015 #define ADD_FONT_SUBST_FORCE 1
1017 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1019 FontSubst
*from_exist
, *to_exist
;
1021 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1023 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1025 list_remove(&from_exist
->entry
);
1026 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
1027 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
1028 HeapFree(GetProcessHeap(), 0, from_exist
);
1034 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1038 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1039 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1042 list_add_tail(subst_list
, &subst
->entry
);
1047 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1048 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1049 HeapFree(GetProcessHeap(), 0, subst
);
1053 static WCHAR
*towstr(UINT cp
, const char *str
)
1058 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1059 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1060 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1064 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1066 CHAR
*p
= strrchr(str
, ',');
1070 nc
->charset
= strtol(p
+1, NULL
, 10);
1073 nc
->name
= towstr(CP_ACP
, str
);
1076 static void LoadSubstList(void)
1080 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1084 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1085 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1086 &hkey
) == ERROR_SUCCESS
) {
1088 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1089 &valuelen
, &datalen
, NULL
, NULL
);
1091 valuelen
++; /* returned value doesn't include room for '\0' */
1092 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1093 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1097 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1098 &dlen
) == ERROR_SUCCESS
) {
1099 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1101 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1102 split_subst_info(&psub
->from
, value
);
1103 split_subst_info(&psub
->to
, data
);
1105 /* Win 2000 doesn't allow mapping between different charsets
1106 or mapping of DEFAULT_CHARSET */
1107 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1108 psub
->to
.charset
== DEFAULT_CHARSET
) {
1109 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1110 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1111 HeapFree(GetProcessHeap(), 0, psub
);
1113 add_font_subst(&font_subst_list
, psub
, 0);
1115 /* reset dlen and vlen */
1119 HeapFree(GetProcessHeap(), 0, data
);
1120 HeapFree(GetProcessHeap(), 0, value
);
1126 /*****************************************************************
1127 * get_name_table_entry
1129 * Supply the platform, encoding, language and name ids in req
1130 * and if the name exists the function will fill in the string
1131 * and string_len members. The string is owned by FreeType so
1132 * don't free it. Returns TRUE if the name is found else FALSE.
1134 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1137 FT_UInt num_names
, name_index
;
1139 if(FT_IS_SFNT(ft_face
))
1141 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1143 for(name_index
= 0; name_index
< num_names
; name_index
++)
1145 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1147 if((name
.platform_id
== req
->platform_id
) &&
1148 (name
.encoding_id
== req
->encoding_id
) &&
1149 (name
.language_id
== req
->language_id
) &&
1150 (name
.name_id
== req
->name_id
))
1152 req
->string
= name
.string
;
1153 req
->string_len
= name
.string_len
;
1160 req
->string_len
= 0;
1164 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1169 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1170 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1171 name
.language_id
= language_id
;
1172 name
.name_id
= name_id
;
1174 if(get_name_table_entry(ft_face
, &name
))
1178 /* String is not nul terminated and string_len is a byte length. */
1179 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1180 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1182 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1183 ret
[i
] = GET_BE_WORD(*tmp
);
1186 TRACE("Got localised name %s\n", debugstr_w(ret
));
1192 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1194 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1195 if (f1
->scalable
) return TRUE
;
1196 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1197 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1200 static inline void free_face( Face
*face
)
1202 HeapFree( GetProcessHeap(), 0, face
->file
);
1203 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1204 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1205 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1206 HeapFree( GetProcessHeap(), 0, face
);
1209 static inline void free_family( Family
*family
)
1211 Face
*face
, *cursor2
;
1213 LIST_FOR_EACH_ENTRY_SAFE( face
, cursor2
, &family
->faces
, Face
, entry
)
1215 list_remove( &face
->entry
);
1218 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1219 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1220 HeapFree( GetProcessHeap(), 0, family
);
1223 static inline int style_order(const Face
*face
)
1225 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1233 case NTM_BOLD
| NTM_ITALIC
:
1236 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1237 debugstr_w(face
->family
->FamilyName
),
1238 debugstr_w(face
->StyleName
),
1244 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1248 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1250 if (faces_equal( face
, cursor
))
1252 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1253 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1254 cursor
->font_version
, face
->font_version
);
1256 if (face
->font_version
<= cursor
->font_version
)
1258 TRACE("Original font %s is newer so skipping %s\n",
1259 debugstr_a(cursor
->file
), debugstr_a(face
->file
));
1264 TRACE("Replacing original %s with %s\n",
1265 debugstr_a(cursor
->file
), debugstr_a(face
->file
));
1266 list_add_before( &cursor
->entry
, &face
->entry
);
1267 face
->family
= family
;
1268 list_remove( &cursor
->entry
);
1269 free_face( cursor
);
1274 TRACE("Adding new %s\n", debugstr_a(face
->file
));
1276 if (style_order( face
) < style_order( cursor
)) break;
1279 list_add_before( &cursor
->entry
, &face
->entry
);
1280 face
->family
= family
;
1284 /****************************************************************
1285 * NB This function stores the ptrs to the strings to save copying.
1286 * Don't free them after calling.
1288 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1290 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1291 family
->FamilyName
= name
;
1292 family
->EnglishName
= english_name
;
1293 list_init( &family
->faces
);
1294 family
->replacement
= &family
->faces
;
1299 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1302 LONG r
= RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, &needed
);
1303 if(r
!= ERROR_SUCCESS
) return r
;
1304 if(type
!= REG_DWORD
|| needed
!= sizeof(DWORD
)) return ERROR_BAD_CONFIGURATION
;
1305 return RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &needed
);
1308 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1310 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1313 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
)
1316 DWORD num_strikes
, max_strike_key_len
;
1318 /* If we have a File Name key then this is a real font, not just the parent
1319 key of a bunch of non-scalable strikes */
1320 if(RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1323 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1324 face
->cached_enum_data
= NULL
;
1326 face
->file
= HeapAlloc(GetProcessHeap(), 0, needed
);
1327 RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, (BYTE
*)face
->file
, &needed
);
1329 face
->StyleName
= strdupW(face_name
);
1331 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1333 WCHAR
*fullName
= HeapAlloc(GetProcessHeap(), 0, needed
);
1334 RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, (BYTE
*)fullName
, &needed
);
1335 face
->FullName
= fullName
;
1338 face
->FullName
= NULL
;
1340 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1341 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1342 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1343 reg_load_dword(hkey_face
, face_vertical_value
, (DWORD
*)&face
->vertical
);
1345 needed
= sizeof(face
->fs
);
1346 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1348 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1350 face
->scalable
= TRUE
;
1351 memset(&face
->size
, 0, sizeof(face
->size
));
1355 face
->scalable
= FALSE
;
1356 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1357 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1358 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1359 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1360 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1362 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1363 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1364 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1367 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1368 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1369 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1370 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1372 insert_face_in_family_list(face
, family
);
1374 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1377 /* do we have any bitmap strikes? */
1378 RegQueryInfoKeyW(hkey_face
, NULL
, NULL
, NULL
, &num_strikes
, &max_strike_key_len
, NULL
, NULL
,
1379 NULL
, NULL
, NULL
, NULL
);
1380 if(num_strikes
!= 0)
1382 WCHAR strike_name
[10];
1383 DWORD strike_index
= 0;
1385 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1386 while(RegEnumKeyExW(hkey_face
, strike_index
++, strike_name
, &needed
,
1387 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1390 RegOpenKeyExW(hkey_face
, strike_name
, 0, KEY_ALL_ACCESS
, &hkey_strike
);
1391 load_face(hkey_strike
, face_name
, family
);
1392 RegCloseKey(hkey_strike
);
1393 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1398 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1400 DWORD max_family_key_len
, size
;
1402 DWORD family_index
= 0;
1406 RegQueryInfoKeyW(hkey_font_cache
, NULL
, NULL
, NULL
, NULL
, &max_family_key_len
, NULL
, NULL
,
1407 NULL
, NULL
, NULL
, NULL
);
1408 family_name
= HeapAlloc(GetProcessHeap(), 0, (max_family_key_len
+ 1) * sizeof(WCHAR
));
1410 size
= max_family_key_len
+ 1;
1411 while(RegEnumKeyExW(hkey_font_cache
, family_index
++, family_name
, &size
,
1412 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1414 WCHAR
*english_family
= NULL
;
1415 DWORD face_index
= 0;
1417 DWORD max_face_key_len
;
1419 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1420 TRACE("opened family key %s\n", debugstr_w(family_name
));
1421 if(RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, NULL
, &size
) == ERROR_SUCCESS
)
1423 english_family
= HeapAlloc(GetProcessHeap(), 0, size
);
1424 RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)english_family
, &size
);
1427 family
= create_family(strdupW(family_name
), english_family
);
1428 list_add_tail(&font_list
, &family
->entry
);
1432 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1433 subst
->from
.name
= strdupW(english_family
);
1434 subst
->from
.charset
= -1;
1435 subst
->to
.name
= strdupW(family_name
);
1436 subst
->to
.charset
= -1;
1437 add_font_subst(&font_subst_list
, subst
, 0);
1440 RegQueryInfoKeyW(hkey_family
, NULL
, NULL
, NULL
, NULL
, &max_face_key_len
, NULL
, NULL
,
1441 NULL
, NULL
, NULL
, NULL
);
1443 face_name
= HeapAlloc(GetProcessHeap(), 0, (max_face_key_len
+ 1) * sizeof(WCHAR
));
1444 size
= max_face_key_len
+ 1;
1445 while(RegEnumKeyExW(hkey_family
, face_index
++, face_name
, &size
,
1446 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1450 RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
);
1451 load_face(hkey_face
, face_name
, family
);
1452 RegCloseKey(hkey_face
);
1453 size
= max_face_key_len
+ 1;
1455 HeapFree(GetProcessHeap(), 0, face_name
);
1456 RegCloseKey(hkey_family
);
1457 size
= max_family_key_len
+ 1;
1460 HeapFree(GetProcessHeap(), 0, family_name
);
1463 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1466 HKEY hkey_wine_fonts
;
1468 /* We don't want to create the fonts key as volatile, so open this first */
1469 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1470 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1471 if(ret
!= ERROR_SUCCESS
)
1473 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1477 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1478 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1479 RegCloseKey(hkey_wine_fonts
);
1483 static void add_face_to_cache(Face
*face
)
1485 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1486 WCHAR
*face_key_name
;
1488 create_font_cache_key(&hkey_font_cache
, NULL
);
1490 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1491 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1492 if(face
->family
->EnglishName
)
1493 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1494 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1497 face_key_name
= face
->StyleName
;
1500 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1501 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1502 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1504 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1507 HeapFree(GetProcessHeap(), 0, face_key_name
);
1509 RegSetValueExA(hkey_face
, "File Name", 0, REG_BINARY
, (BYTE
*)face
->file
, strlen(face
->file
) + 1);
1511 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1512 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1514 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1515 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1516 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1517 reg_save_dword(hkey_face
, face_vertical_value
, face
->vertical
);
1519 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1523 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1524 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1525 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1526 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1527 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1528 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1530 RegCloseKey(hkey_face
);
1531 RegCloseKey(hkey_family
);
1532 RegCloseKey(hkey_font_cache
);
1535 static WCHAR
*prepend_at(WCHAR
*family
)
1542 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1544 strcpyW(str
+ 1, family
);
1545 HeapFree(GetProcessHeap(), 0, family
);
1549 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1551 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1552 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1554 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID() );
1560 else if (!strcmpiW( *name
, *english
))
1562 HeapFree( GetProcessHeap(), 0, *english
);
1568 *name
= prepend_at( *name
);
1569 *english
= prepend_at( *english
);
1573 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1576 WCHAR
*name
, *english_name
;
1578 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1580 family
= find_family_from_name( name
);
1584 family
= create_family( name
, english_name
);
1585 list_add_tail( &font_list
, &family
->entry
);
1589 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1590 subst
->from
.name
= strdupW( english_name
);
1591 subst
->from
.charset
= -1;
1592 subst
->to
.name
= strdupW( name
);
1593 subst
->to
.charset
= -1;
1594 add_font_subst( &font_subst_list
, subst
, 0 );
1599 HeapFree( GetProcessHeap(), 0, name
);
1600 HeapFree( GetProcessHeap(), 0, english_name
);
1606 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1608 FT_Fixed version
= 0;
1611 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1612 if (header
) version
= header
->Font_Revision
;
1617 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1620 FT_ULong table_size
= 0;
1622 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1623 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1624 if (flags
== 0) flags
= NTM_REGULAR
;
1626 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1627 flags
|= NTM_PS_OPENTYPE
;
1632 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1634 int internal_leading
= 0;
1635 FT_WinFNT_HeaderRec winfnt_header
;
1637 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1638 internal_leading
= winfnt_header
.internal_leading
;
1640 return internal_leading
;
1643 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1648 FT_WinFNT_HeaderRec winfnt_header
;
1651 memset( fs
, 0, sizeof(*fs
) );
1653 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1656 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1657 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1658 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1659 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1661 if (os2
->version
== 0)
1663 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1664 fs
->fsCsb
[0] = FS_LATIN1
;
1666 fs
->fsCsb
[0] = FS_SYMBOL
;
1670 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1671 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1676 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1678 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1679 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1680 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1685 if (fs
->fsCsb
[0] == 0)
1687 /* let's see if we can find any interesting cmaps */
1688 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1690 switch (ft_face
->charmaps
[i
]->encoding
)
1692 case FT_ENCODING_UNICODE
:
1693 case FT_ENCODING_APPLE_ROMAN
:
1694 fs
->fsCsb
[0] |= FS_LATIN1
;
1696 case FT_ENCODING_MS_SYMBOL
:
1697 fs
->fsCsb
[0] |= FS_SYMBOL
;
1706 #define ADDFONT_EXTERNAL_FONT 0x01
1707 #define ADDFONT_FORCE_BITMAP 0x02
1708 #define ADDFONT_ADD_TO_CACHE 0x04
1710 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1711 DWORD flags
, BOOL vertical
)
1713 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1714 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1716 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1717 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1720 face
->file
= strdupA( file
);
1721 face
->font_data_ptr
= NULL
;
1722 face
->font_data_size
= 0;
1727 face
->font_data_ptr
= font_data_ptr
;
1728 face
->font_data_size
= font_data_size
;
1731 face
->face_index
= face_index
;
1732 get_fontsig( ft_face
, &face
->fs
);
1733 face
->ntmFlags
= get_ntm_flags( ft_face
);
1734 face
->font_version
= get_font_version( ft_face
);
1736 if (FT_IS_SCALABLE( ft_face
))
1738 memset( &face
->size
, 0, sizeof(face
->size
) );
1739 face
->scalable
= TRUE
;
1743 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1744 size
->height
, size
->width
, size
->size
>> 6,
1745 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1746 face
->size
.height
= size
->height
;
1747 face
->size
.width
= size
->width
;
1748 face
->size
.size
= size
->size
;
1749 face
->size
.x_ppem
= size
->x_ppem
;
1750 face
->size
.y_ppem
= size
->y_ppem
;
1751 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1752 face
->scalable
= FALSE
;
1755 face
->vertical
= vertical
;
1756 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1757 face
->family
= NULL
;
1758 face
->cached_enum_data
= NULL
;
1760 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1761 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1762 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1763 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1768 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1769 FT_Long face_index
, DWORD flags
, BOOL vertical
)
1774 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
, vertical
);
1775 family
= get_family( ft_face
, vertical
);
1776 if (!insert_face_in_family_list( face
, family
))
1782 if (flags
& ADDFONT_ADD_TO_CACHE
)
1783 add_face_to_cache( face
);
1785 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1786 debugstr_w(face
->StyleName
));
1789 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1790 FT_Long face_index
, BOOL allow_bitmap
)
1798 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1799 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1803 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1804 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1809 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1813 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1814 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1816 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1820 if (!FT_IS_SFNT( ft_face
))
1822 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1824 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1830 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1831 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1832 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1834 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1835 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1839 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1840 we don't want to load these. */
1841 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1845 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1847 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1853 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1855 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1861 pFT_Done_Face( ft_face
);
1865 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1868 FT_Long face_index
= 0, num_faces
;
1871 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1872 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1874 #ifdef HAVE_CARBON_CARBON_H
1877 char **mac_list
= expand_mac_font(file
);
1880 BOOL had_one
= FALSE
;
1882 for(cursor
= mac_list
; *cursor
; cursor
++)
1885 AddFontToList(*cursor
, NULL
, 0, flags
);
1886 HeapFree(GetProcessHeap(), 0, *cursor
);
1888 HeapFree(GetProcessHeap(), 0, mac_list
);
1893 #endif /* HAVE_CARBON_CARBON_H */
1896 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_FORCE_BITMAP
);
1897 if (!ft_face
) return 0;
1899 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1901 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1902 pFT_Done_Face(ft_face
);
1906 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1909 if (FT_HAS_VERTICAL(ft_face
))
1911 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1915 num_faces
= ft_face
->num_faces
;
1916 pFT_Done_Face(ft_face
);
1917 } while(num_faces
> ++face_index
);
1921 static void DumpFontList(void)
1925 struct list
*family_elem_ptr
, *face_elem_ptr
;
1927 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1928 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1929 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1930 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1931 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1932 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1934 TRACE(" %d", face
->size
.height
);
1941 /***********************************************************
1942 * The replacement list is a way to map an entire font
1943 * family onto another family. For example adding
1945 * [HKCU\Software\Wine\Fonts\Replacements]
1946 * "Wingdings"="Winedings"
1948 * would enumerate the Winedings font both as Winedings and
1949 * Wingdings. However if a real Wingdings font is present the
1950 * replacement does not take place.
1953 static void LoadReplaceList(void)
1956 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1961 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1962 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1964 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1965 &valuelen
, &datalen
, NULL
, NULL
);
1967 valuelen
++; /* returned value doesn't include room for '\0' */
1968 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1969 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1973 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1974 &dlen
) == ERROR_SUCCESS
) {
1975 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1976 /* "NewName"="Oldname" */
1977 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1979 if(!find_family_from_any_name(value
))
1981 Family
* const family
= find_family_from_any_name(data
);
1984 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
1985 if (new_family
!= NULL
)
1987 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
1988 new_family
->FamilyName
= strdupW(value
);
1989 new_family
->EnglishName
= NULL
;
1990 list_init(&new_family
->faces
);
1991 new_family
->replacement
= &family
->faces
;
1992 list_add_tail(&font_list
, &new_family
->entry
);
1997 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2002 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2004 /* reset dlen and vlen */
2008 HeapFree(GetProcessHeap(), 0, data
);
2009 HeapFree(GetProcessHeap(), 0, value
);
2014 static const WCHAR
*font_links_list
[] =
2016 Lucida_Sans_Unicode
,
2017 Microsoft_Sans_Serif
,
2021 static const struct font_links_defaults_list
2023 /* Keyed off substitution for "MS Shell Dlg" */
2024 const WCHAR
*shelldlg
;
2025 /* Maximum of four substitutes, plus terminating NULL pointer */
2026 const WCHAR
*substitutes
[5];
2027 } font_links_defaults_list
[] =
2029 /* Non East-Asian */
2030 { Tahoma
, /* FIXME unverified ordering */
2031 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2033 /* Below lists are courtesy of
2034 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2038 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2040 /* Chinese Simplified */
2042 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2046 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2048 /* Chinese Traditional */
2050 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2055 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2057 SYSTEM_LINKS
*font_link
;
2059 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2061 if(!strcmpiW(font_link
->font_name
, name
))
2068 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2080 SYSTEM_LINKS
*font_link
;
2082 psub
= get_font_subst(&font_subst_list
, name
, -1);
2083 /* Don't store fonts that are only substitutes for other fonts */
2086 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2090 font_link
= find_font_link(name
);
2091 if (font_link
== NULL
)
2093 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2094 font_link
->font_name
= strdupW(name
);
2095 list_init(&font_link
->links
);
2096 list_add_tail(&system_links
, &font_link
->entry
);
2099 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2100 for (i
= 0; values
[i
] != NULL
; i
++)
2102 const struct list
*face_list
;
2103 CHILD_FONT
*child_font
;
2106 if (!strcmpiW(name
,value
))
2108 psub
= get_font_subst(&font_subst_list
, value
, -1);
2110 value
= psub
->to
.name
;
2111 family
= find_family_from_name(value
);
2115 /* Use first extant filename for this Family */
2116 face_list
= get_face_list_from_family(family
);
2117 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2121 file
= strrchr(face
->file
, '/');
2130 fileW
= towstr(CP_UNIXCP
, file
);
2132 face
= find_face_from_filename(fileW
, value
);
2135 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2139 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2140 child_font
->face
= face
;
2141 child_font
->font
= NULL
;
2142 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2143 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2144 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2145 list_add_tail(&font_link
->links
, &child_font
->entry
);
2147 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2148 HeapFree(GetProcessHeap(), 0, fileW
);
2154 /*************************************************************
2157 static BOOL
init_system_links(void)
2161 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2162 WCHAR
*value
, *data
;
2163 WCHAR
*entry
, *next
;
2164 SYSTEM_LINKS
*font_link
, *system_font_link
;
2165 CHILD_FONT
*child_font
;
2166 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2167 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2168 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2173 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2175 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2176 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2177 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2178 val_len
= max_val
+ 1;
2179 data_len
= max_data
;
2181 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2183 psub
= get_font_subst(&font_subst_list
, value
, -1);
2184 /* Don't store fonts that are only substitutes for other fonts */
2187 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2190 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2191 font_link
->font_name
= strdupW(value
);
2192 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2193 list_init(&font_link
->links
);
2194 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2197 CHILD_FONT
*child_font
;
2199 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2201 next
= entry
+ strlenW(entry
) + 1;
2203 face_name
= strchrW(entry
, ',');
2207 while(isspaceW(*face_name
))
2210 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2212 face_name
= psub
->to
.name
;
2214 face
= find_face_from_filename(entry
, face_name
);
2217 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2221 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2222 child_font
->face
= face
;
2223 child_font
->font
= NULL
;
2224 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2225 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2226 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2227 list_add_tail(&font_link
->links
, &child_font
->entry
);
2229 list_add_tail(&system_links
, &font_link
->entry
);
2231 val_len
= max_val
+ 1;
2232 data_len
= max_data
;
2235 HeapFree(GetProcessHeap(), 0, value
);
2236 HeapFree(GetProcessHeap(), 0, data
);
2241 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2243 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2247 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2249 const FontSubst
*psub2
;
2250 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2252 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2254 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2255 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2257 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2258 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2260 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2262 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2268 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2271 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2272 system_font_link
->font_name
= strdupW(System
);
2273 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2274 list_init(&system_font_link
->links
);
2276 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2279 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2280 child_font
->face
= face
;
2281 child_font
->font
= NULL
;
2282 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2283 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2284 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2285 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2287 font_link
= find_font_link(Tahoma
);
2288 if (font_link
!= NULL
)
2290 CHILD_FONT
*font_link_entry
;
2291 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2293 CHILD_FONT
*new_child
;
2294 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2295 new_child
->face
= font_link_entry
->face
;
2296 new_child
->font
= NULL
;
2297 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2298 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2299 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2302 list_add_tail(&system_links
, &system_font_link
->entry
);
2306 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2309 struct dirent
*dent
;
2310 char path
[MAX_PATH
];
2312 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2314 dir
= opendir(dirname
);
2316 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2319 while((dent
= readdir(dir
)) != NULL
) {
2320 struct stat statbuf
;
2322 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2325 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2327 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2329 if(stat(path
, &statbuf
) == -1)
2331 WARN("Can't stat %s\n", debugstr_a(path
));
2334 if(S_ISDIR(statbuf
.st_mode
))
2335 ReadFontDir(path
, external_fonts
);
2338 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2339 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2340 AddFontToList(path
, NULL
, 0, addfont_flags
);
2347 #ifdef SONAME_LIBFONTCONFIG
2348 static void load_fontconfig_fonts(void)
2350 void *fc_handle
= NULL
;
2359 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2361 TRACE("Wine cannot find the fontconfig library (%s).\n",
2362 SONAME_LIBFONTCONFIG
);
2365 #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;}
2366 LOAD_FUNCPTR(FcConfigGetCurrent
);
2367 LOAD_FUNCPTR(FcFontList
);
2368 LOAD_FUNCPTR(FcFontSetDestroy
);
2369 LOAD_FUNCPTR(FcInit
);
2370 LOAD_FUNCPTR(FcObjectSetAdd
);
2371 LOAD_FUNCPTR(FcObjectSetCreate
);
2372 LOAD_FUNCPTR(FcObjectSetDestroy
);
2373 LOAD_FUNCPTR(FcPatternCreate
);
2374 LOAD_FUNCPTR(FcPatternDestroy
);
2375 LOAD_FUNCPTR(FcPatternGetBool
);
2376 LOAD_FUNCPTR(FcPatternGetString
);
2379 if(!pFcInit()) return;
2381 config
= pFcConfigGetCurrent();
2382 pat
= pFcPatternCreate();
2383 os
= pFcObjectSetCreate();
2384 pFcObjectSetAdd(os
, FC_FILE
);
2385 pFcObjectSetAdd(os
, FC_SCALABLE
);
2386 fontset
= pFcFontList(config
, pat
, os
);
2387 if(!fontset
) return;
2388 for(i
= 0; i
< fontset
->nfont
; i
++) {
2391 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2393 TRACE("fontconfig: %s\n", file
);
2395 /* We're just interested in OT/TT fonts for now, so this hack just
2396 picks up the scalable fonts without extensions .pf[ab] to save time
2397 loading every other font */
2399 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2401 TRACE("not scalable\n");
2405 len
= strlen( file
);
2406 if(len
< 4) continue;
2407 ext
= &file
[ len
- 3 ];
2408 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2409 AddFontToList(file
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2411 pFcFontSetDestroy(fontset
);
2412 pFcObjectSetDestroy(os
);
2413 pFcPatternDestroy(pat
);
2418 #elif defined(HAVE_CARBON_CARBON_H)
2420 static void load_mac_font_callback(const void *value
, void *context
)
2422 CFStringRef pathStr
= value
;
2426 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2427 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2428 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2430 TRACE("font file %s\n", path
);
2431 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2433 HeapFree(GetProcessHeap(), 0, path
);
2436 static void load_mac_fonts(void)
2438 CFStringRef removeDupesKey
;
2439 CFBooleanRef removeDupesValue
;
2440 CFDictionaryRef options
;
2441 CTFontCollectionRef col
;
2443 CFMutableSetRef paths
;
2446 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2447 removeDupesValue
= kCFBooleanTrue
;
2448 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2449 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2450 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2451 if (options
) CFRelease(options
);
2454 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2458 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2462 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2466 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2469 WARN("CFSetCreateMutable failed\n");
2474 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2476 CTFontDescriptorRef desc
;
2485 desc
= CFArrayGetValueAtIndex(descs
, i
);
2487 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2488 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2489 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2490 if (!font
) continue;
2492 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2499 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2501 if (status
!= noErr
) continue;
2503 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2506 ext
= CFURLCopyPathExtension(url
);
2509 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2510 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2519 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2521 if (!path
) continue;
2523 CFSetAddValue(paths
, path
);
2529 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2535 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2538 const char *data_dir
= wine_get_data_dir();
2540 if (!data_dir
) data_dir
= wine_get_build_dir();
2547 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2549 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2551 strcpy(unix_name
, data_dir
);
2552 strcat(unix_name
, "/fonts/");
2554 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2556 EnterCriticalSection( &freetype_cs
);
2557 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2558 LeaveCriticalSection( &freetype_cs
);
2559 HeapFree(GetProcessHeap(), 0, unix_name
);
2564 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2566 static const WCHAR slashW
[] = {'\\','\0'};
2568 WCHAR windowsdir
[MAX_PATH
];
2571 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2572 strcatW(windowsdir
, fontsW
);
2573 strcatW(windowsdir
, slashW
);
2574 strcatW(windowsdir
, file
);
2575 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2576 EnterCriticalSection( &freetype_cs
);
2577 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2578 LeaveCriticalSection( &freetype_cs
);
2579 HeapFree(GetProcessHeap(), 0, unixname
);
2584 static void load_system_fonts(void)
2587 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2588 const WCHAR
* const *value
;
2590 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2593 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2594 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2595 strcatW(windowsdir
, fontsW
);
2596 for(value
= SystemFontValues
; *value
; value
++) {
2597 dlen
= sizeof(data
);
2598 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2602 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2603 if((unixname
= wine_get_unix_file_name(pathW
))) {
2604 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2605 HeapFree(GetProcessHeap(), 0, unixname
);
2608 load_font_from_data_dir(data
);
2615 /*************************************************************
2617 * This adds registry entries for any externally loaded fonts
2618 * (fonts from fontconfig or FontDirs). It also deletes entries
2619 * of no longer existing fonts.
2622 static void update_reg_entries(void)
2624 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2629 struct list
*family_elem_ptr
, *face_elem_ptr
;
2631 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2632 static const WCHAR spaceW
[] = {' ', '\0'};
2635 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2636 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2637 ERR("Can't create Windows font reg key\n");
2641 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2642 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2643 ERR("Can't create Windows font reg key\n");
2647 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2648 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2649 ERR("Can't create external font reg key\n");
2653 /* enumerate the fonts and add external ones to the two keys */
2655 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2656 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2657 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2658 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2659 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2660 if(!face
->external
) continue;
2662 if (!(face
->ntmFlags
& NTM_REGULAR
))
2663 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2664 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2665 strcpyW(valueW
, family
->FamilyName
);
2666 if(len
!= len_fam
) {
2667 strcatW(valueW
, spaceW
);
2668 strcatW(valueW
, face
->StyleName
);
2670 strcatW(valueW
, TrueType
);
2672 file
= wine_get_dos_file_name(face
->file
);
2674 len
= strlenW(file
) + 1;
2677 if((path
= strrchr(face
->file
, '/')) == NULL
)
2681 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2683 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2684 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2686 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2687 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2688 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2690 HeapFree(GetProcessHeap(), 0, file
);
2691 HeapFree(GetProcessHeap(), 0, valueW
);
2695 if(external_key
) RegCloseKey(external_key
);
2696 if(win9x_key
) RegCloseKey(win9x_key
);
2697 if(winnt_key
) RegCloseKey(winnt_key
);
2701 static void delete_external_font_keys(void)
2703 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2704 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2708 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2709 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2710 ERR("Can't create Windows font reg key\n");
2714 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2715 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2716 ERR("Can't create Windows font reg key\n");
2720 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2721 ERR("Can't create external font reg key\n");
2725 /* Delete all external fonts added last time */
2727 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2728 &valuelen
, &datalen
, NULL
, NULL
);
2729 valuelen
++; /* returned value doesn't include room for '\0' */
2730 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2731 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2733 dlen
= datalen
* sizeof(WCHAR
);
2736 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2737 &dlen
) == ERROR_SUCCESS
) {
2739 RegDeleteValueW(winnt_key
, valueW
);
2740 RegDeleteValueW(win9x_key
, valueW
);
2741 /* reset dlen and vlen */
2745 HeapFree(GetProcessHeap(), 0, data
);
2746 HeapFree(GetProcessHeap(), 0, valueW
);
2748 /* Delete the old external fonts key */
2749 RegCloseKey(external_key
);
2750 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2753 if(win9x_key
) RegCloseKey(win9x_key
);
2754 if(winnt_key
) RegCloseKey(winnt_key
);
2757 /*************************************************************
2758 * WineEngAddFontResourceEx
2761 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2767 if (ft_handle
) /* do it only if we have freetype up and running */
2772 FIXME("Ignoring flags %x\n", flags
);
2774 if((unixname
= wine_get_unix_file_name(file
)))
2776 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2778 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2779 EnterCriticalSection( &freetype_cs
);
2780 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2781 LeaveCriticalSection( &freetype_cs
);
2782 HeapFree(GetProcessHeap(), 0, unixname
);
2784 if (!ret
&& !strchrW(file
, '\\')) {
2785 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2786 ret
= load_font_from_winfonts_dir(file
);
2788 /* Try in datadir/fonts (or builddir/fonts),
2789 * needed for Magic the Gathering Online
2791 ret
= load_font_from_data_dir(file
);
2798 /*************************************************************
2799 * WineEngAddFontMemResourceEx
2802 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2806 if (ft_handle
) /* do it only if we have freetype up and running */
2808 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2810 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2811 memcpy(pFontCopy
, pbFont
, cbFont
);
2813 EnterCriticalSection( &freetype_cs
);
2814 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2815 LeaveCriticalSection( &freetype_cs
);
2819 TRACE("AddFontToList failed\n");
2820 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2823 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2824 * For now return something unique but quite random
2826 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2827 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2834 /*************************************************************
2835 * WineEngRemoveFontResourceEx
2838 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2841 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2845 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
2851 if (!font_file
) return NULL
;
2853 file_len
= strlenW( font_file
);
2855 if (font_path
&& font_path
[0])
2857 int path_len
= strlenW( font_path
);
2858 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
2859 if (!fullname
) return NULL
;
2860 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
2861 fullname
[path_len
] = '\\';
2862 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
2866 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
2867 if (!len
) return NULL
;
2868 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2869 if (!fullname
) return NULL
;
2870 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
2873 unix_name
= wine_get_unix_file_name( fullname
);
2874 HeapFree( GetProcessHeap(), 0, fullname
);
2878 #include <pshpack1.h>
2881 WORD num_of_resources
;
2885 CHAR dfCopyright
[60];
2891 WORD dfInternalLeading
;
2892 WORD dfExternalLeading
;
2900 BYTE dfPitchAndFamily
;
2911 CHAR szFaceName
[LF_FACESIZE
];
2914 #include <poppack.h>
2916 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
2917 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
2919 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
2921 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
2924 WCHAR
*name
, *english_name
;
2926 NEWTEXTMETRICEXW ntm
;
2929 if (!ft_face
) return FALSE
;
2930 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0, FALSE
);
2931 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
2932 family
= create_family( name
, english_name
);
2933 insert_face_in_family_list( face
, family
);
2934 pFT_Done_Face( ft_face
);
2936 GetEnumStructs( face
, &elf
, &ntm
, &type
);
2937 free_family( family
);
2939 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
2941 memset( fd
, 0, sizeof(*fd
) );
2943 fd
->num_of_resources
= 1;
2945 fd
->dfVersion
= 0x200;
2946 fd
->dfSize
= sizeof(*fd
);
2947 strcpy( fd
->dfCopyright
, "Wine fontdir" );
2948 fd
->dfType
= 0x4003; /* 0x0080 set if private */
2949 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
2951 fd
->dfHorizRes
= 72;
2952 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
2953 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
2954 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
2955 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
2956 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
2957 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
2958 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
2959 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
2961 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
2962 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
2963 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
2964 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
2965 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
2966 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
2967 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
2968 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
2969 fd
->dfWidthBytes
= 0;
2971 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
2973 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
2978 #define NE_FFLAGS_LIBMODULE 0x8000
2979 #define NE_OSFLAGS_WINDOWS 0x02
2981 static const char dos_string
[0x40] = "This is a TrueType resource file";
2982 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
2984 #include <pshpack2.h>
3005 struct ne_typeinfo fontdir_type
;
3006 struct ne_nameinfo fontdir_name
;
3007 struct ne_typeinfo scalable_type
;
3008 struct ne_nameinfo scalable_name
;
3010 BYTE fontdir_res_name
[8];
3013 #include <poppack.h>
3015 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3019 DWORD size
, written
;
3021 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3022 char *font_fileA
, *last_part
, *ext
;
3023 IMAGE_DOS_HEADER dos
;
3024 IMAGE_OS2_HEADER ne
=
3026 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3028 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3029 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3031 struct rsrc_tab rsrc_tab
=
3035 { 0, 0, 0x0c50, 0x2c, 0 },
3037 { 0, 0, 0x0c50, 0x8001, 0 },
3039 { 7,'F','O','N','T','D','I','R'}
3042 memset( &dos
, 0, sizeof(dos
) );
3043 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3044 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3046 /* import name is last part\0, resident name is last part without extension
3047 non-resident name is "FONTRES:" + lfFaceName */
3049 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3050 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3051 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3053 last_part
= strrchr( font_fileA
, '\\' );
3054 if (last_part
) last_part
++;
3055 else last_part
= font_fileA
;
3056 import_name_len
= strlen( last_part
) + 1;
3058 ext
= strchr( last_part
, '.' );
3059 if (ext
) res_name_len
= ext
- last_part
;
3060 else res_name_len
= import_name_len
- 1;
3062 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3064 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3065 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3066 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3067 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3069 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3071 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3072 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3073 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3074 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3076 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3077 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3081 HeapFree( GetProcessHeap(), 0, font_fileA
);
3085 memcpy( ptr
, &dos
, sizeof(dos
) );
3086 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3087 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3089 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3090 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3092 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3093 *ptr
++ = res_name_len
;
3094 memcpy( ptr
, last_part
, res_name_len
);
3096 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3097 *ptr
++ = import_name_len
;
3098 memcpy( ptr
, last_part
, import_name_len
);
3100 ptr
= start
+ ne
.ne_nrestab
;
3101 *ptr
++ = non_res_name_len
;
3102 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3103 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3105 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3106 memcpy( ptr
, font_fileA
, font_file_len
);
3108 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3109 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3111 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3112 if (file
!= INVALID_HANDLE_VALUE
)
3114 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3116 CloseHandle( file
);
3119 HeapFree( GetProcessHeap(), 0, start
);
3120 HeapFree( GetProcessHeap(), 0, font_fileA
);
3125 /*************************************************************
3126 * WineEngCreateScalableFontResource
3129 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3130 LPCWSTR font_file
, LPCWSTR font_path
)
3132 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3133 struct fontdir fontdir
;
3136 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3137 SetLastError( ERROR_INVALID_PARAMETER
);
3140 if (hidden
) fontdir
.dfType
|= 0x80;
3141 ret
= create_fot( resource
, font_file
, &fontdir
);
3144 HeapFree( GetProcessHeap(), 0, unix_name
);
3148 static const struct nls_update_font_list
3150 UINT ansi_cp
, oem_cp
;
3151 const char *oem
, *fixed
, *system
;
3152 const char *courier
, *serif
, *small
, *sserif
;
3153 /* these are for font substitutes */
3154 const char *shelldlg
, *tmsrmn
;
3155 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3159 const char *from
, *to
;
3160 } arial_0
, courier_new_0
, times_new_roman_0
;
3161 } nls_update_font_list
[] =
3163 /* Latin 1 (United States) */
3164 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3165 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3166 "Tahoma","Times New Roman",
3167 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3170 /* Latin 1 (Multilingual) */
3171 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3172 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3173 "Tahoma","Times New Roman", /* FIXME unverified */
3174 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3177 /* Eastern Europe */
3178 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3179 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
3180 "Tahoma","Times New Roman", /* FIXME unverified */
3181 "Fixedsys,238", "System,238",
3182 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3183 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3184 { "Arial CE,0", "Arial,238" },
3185 { "Courier New CE,0", "Courier New,238" },
3186 { "Times New Roman CE,0", "Times New Roman,238" }
3189 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3190 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
3191 "Tahoma","Times New Roman", /* FIXME unverified */
3192 "Fixedsys,204", "System,204",
3193 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3194 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3195 { "Arial Cyr,0", "Arial,204" },
3196 { "Courier New Cyr,0", "Courier New,204" },
3197 { "Times New Roman Cyr,0", "Times New Roman,204" }
3200 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3201 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
3202 "Tahoma","Times New Roman", /* FIXME unverified */
3203 "Fixedsys,161", "System,161",
3204 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3205 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3206 { "Arial Greek,0", "Arial,161" },
3207 { "Courier New Greek,0", "Courier New,161" },
3208 { "Times New Roman Greek,0", "Times New Roman,161" }
3211 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3212 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
3213 "Tahoma","Times New Roman", /* FIXME unverified */
3214 "Fixedsys,162", "System,162",
3215 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3216 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3217 { "Arial Tur,0", "Arial,162" },
3218 { "Courier New Tur,0", "Courier New,162" },
3219 { "Times New Roman Tur,0", "Times New Roman,162" }
3222 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3223 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
3224 "Tahoma","Times New Roman", /* FIXME unverified */
3225 "Fixedsys,177", "System,177",
3226 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3227 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3231 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3232 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
3233 "Tahoma","Times New Roman", /* FIXME unverified */
3234 "Fixedsys,178", "System,178",
3235 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3236 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3240 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3241 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
3242 "Tahoma","Times New Roman", /* FIXME unverified */
3243 "Fixedsys,186", "System,186",
3244 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3245 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3246 { "Arial Baltic,0", "Arial,186" },
3247 { "Courier New Baltic,0", "Courier New,186" },
3248 { "Times New Roman Baltic,0", "Times New Roman,186" }
3251 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3252 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3253 "Tahoma","Times New Roman", /* FIXME unverified */
3254 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3258 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3259 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
3260 "Tahoma","Times New Roman", /* FIXME unverified */
3261 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3265 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3266 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
3267 "MS UI Gothic","MS Serif",
3268 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3271 /* Chinese Simplified */
3272 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3273 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3274 "SimSun", "NSimSun",
3275 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3279 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3280 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3282 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3285 /* Chinese Traditional */
3286 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3287 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3288 "PMingLiU", "MingLiU",
3289 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3294 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3296 return ( ansi_cp
== 932 /* CP932 for Japanese */
3297 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3298 || ansi_cp
== 949 /* CP949 for Korean */
3299 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3302 static inline HKEY
create_fonts_NT_registry_key(void)
3306 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3307 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3311 static inline HKEY
create_fonts_9x_registry_key(void)
3315 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3316 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3320 static inline HKEY
create_config_fonts_registry_key(void)
3324 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3325 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3329 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
3331 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3332 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3333 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
3334 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3337 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3340 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3342 RegDeleteValueA(hkey
, name
);
3345 static void update_font_info(void)
3347 char buf
[40], cpbuf
[40];
3350 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3353 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3356 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3357 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3358 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3359 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3360 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3362 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3363 if (is_dbcs_ansi_cp(ansi_cp
))
3364 use_default_fallback
= TRUE
;
3367 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3369 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
3374 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
3376 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
3378 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3381 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3385 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3386 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3388 hkey
= create_config_fonts_registry_key();
3389 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3390 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3391 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3394 hkey
= create_fonts_NT_registry_key();
3395 add_font_list(hkey
, &nls_update_font_list
[i
]);
3398 hkey
= create_fonts_9x_registry_key();
3399 add_font_list(hkey
, &nls_update_font_list
[i
]);
3402 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3404 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3405 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3406 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3407 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3409 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3410 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3411 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3412 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3413 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3414 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3415 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3416 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3418 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3419 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3420 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3428 /* Delete the FontSubstitutes from other locales */
3429 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3431 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3432 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3433 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3439 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3442 static BOOL
init_freetype(void)
3444 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3447 "Wine cannot find the FreeType font library. To enable Wine to\n"
3448 "use TrueType fonts please install a version of FreeType greater than\n"
3449 "or equal to 2.0.5.\n"
3450 "http://www.freetype.org\n");
3454 #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;}
3456 LOAD_FUNCPTR(FT_Done_Face
)
3457 LOAD_FUNCPTR(FT_Get_Char_Index
)
3458 LOAD_FUNCPTR(FT_Get_First_Char
)
3459 LOAD_FUNCPTR(FT_Get_Module
)
3460 LOAD_FUNCPTR(FT_Get_Next_Char
)
3461 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3462 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3463 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3464 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3465 LOAD_FUNCPTR(FT_Init_FreeType
)
3466 LOAD_FUNCPTR(FT_Library_Version
)
3467 LOAD_FUNCPTR(FT_Load_Glyph
)
3468 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3469 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3470 #ifndef FT_MULFIX_INLINED
3471 LOAD_FUNCPTR(FT_MulFix
)
3473 LOAD_FUNCPTR(FT_New_Face
)
3474 LOAD_FUNCPTR(FT_New_Memory_Face
)
3475 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3476 LOAD_FUNCPTR(FT_Outline_Transform
)
3477 LOAD_FUNCPTR(FT_Outline_Translate
)
3478 LOAD_FUNCPTR(FT_Render_Glyph
)
3479 LOAD_FUNCPTR(FT_Select_Charmap
)
3480 LOAD_FUNCPTR(FT_Set_Charmap
)
3481 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3482 LOAD_FUNCPTR(FT_Vector_Transform
)
3483 LOAD_FUNCPTR(FT_Vector_Unit
)
3485 /* Don't warn if these ones are missing */
3486 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3487 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3488 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3491 if(pFT_Init_FreeType(&library
) != 0) {
3492 ERR("Can't init FreeType library\n");
3493 wine_dlclose(ft_handle
, NULL
, 0);
3497 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3499 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3500 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3501 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3502 ((FT_Version
.patch
) & 0x0000ff);
3504 font_driver
= &freetype_funcs
;
3509 "Wine cannot find certain functions that it needs inside the FreeType\n"
3510 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3511 "FreeType to at least version 2.1.4.\n"
3512 "http://www.freetype.org\n");
3513 wine_dlclose(ft_handle
, NULL
, 0);
3518 static void init_font_list(void)
3520 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3521 static const WCHAR pathW
[] = {'P','a','t','h',0};
3523 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3524 WCHAR windowsdir
[MAX_PATH
];
3526 const char *data_dir
;
3528 delete_external_font_keys();
3530 /* load the system bitmap fonts */
3531 load_system_fonts();
3533 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3534 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3535 strcatW(windowsdir
, fontsW
);
3536 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3538 ReadFontDir(unixname
, FALSE
);
3539 HeapFree(GetProcessHeap(), 0, unixname
);
3542 /* load the system truetype fonts */
3543 data_dir
= wine_get_data_dir();
3544 if (!data_dir
) data_dir
= wine_get_build_dir();
3545 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3547 strcpy(unixname
, data_dir
);
3548 strcat(unixname
, "/fonts/");
3549 ReadFontDir(unixname
, TRUE
);
3550 HeapFree(GetProcessHeap(), 0, unixname
);
3553 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3554 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3555 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3557 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3558 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3559 &hkey
) == ERROR_SUCCESS
)
3561 LPWSTR data
, valueW
;
3562 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3563 &valuelen
, &datalen
, NULL
, NULL
);
3565 valuelen
++; /* returned value doesn't include room for '\0' */
3566 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3567 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3570 dlen
= datalen
* sizeof(WCHAR
);
3572 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3573 &dlen
) == ERROR_SUCCESS
)
3575 if(data
[0] && (data
[1] == ':'))
3577 if((unixname
= wine_get_unix_file_name(data
)))
3579 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3580 HeapFree(GetProcessHeap(), 0, unixname
);
3583 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3585 WCHAR pathW
[MAX_PATH
];
3586 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3589 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3590 if((unixname
= wine_get_unix_file_name(pathW
)))
3592 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3593 HeapFree(GetProcessHeap(), 0, unixname
);
3596 load_font_from_data_dir(data
);
3598 /* reset dlen and vlen */
3603 HeapFree(GetProcessHeap(), 0, data
);
3604 HeapFree(GetProcessHeap(), 0, valueW
);
3608 #ifdef SONAME_LIBFONTCONFIG
3609 load_fontconfig_fonts();
3610 #elif defined(HAVE_CARBON_CARBON_H)
3614 /* then look in any directories that we've specified in the config file */
3615 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3616 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3622 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3624 len
+= sizeof(WCHAR
);
3625 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3626 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3628 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3629 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3630 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3631 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3636 LPSTR next
= strchr( ptr
, ':' );
3637 if (next
) *next
++ = 0;
3638 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3639 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3641 strcpy( unixname
, home
);
3642 strcat( unixname
, ptr
+ 1 );
3643 ReadFontDir( unixname
, TRUE
);
3644 HeapFree( GetProcessHeap(), 0, unixname
);
3647 ReadFontDir( ptr
, TRUE
);
3650 HeapFree( GetProcessHeap(), 0, valueA
);
3652 HeapFree( GetProcessHeap(), 0, valueW
);
3658 static BOOL
move_to_front(const WCHAR
*name
)
3660 Family
*family
, *cursor2
;
3661 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3663 if(!strcmpiW(family
->FamilyName
, name
))
3665 list_remove(&family
->entry
);
3666 list_add_head(&font_list
, &family
->entry
);
3673 static BOOL
set_default(const WCHAR
**name_list
)
3677 if (move_to_front(*name_list
)) return TRUE
;
3684 static void reorder_font_list(void)
3686 set_default( default_serif_list
);
3687 set_default( default_fixed_list
);
3688 set_default( default_sans_list
);
3691 /*************************************************************
3694 * Initialize FreeType library and create a list of available faces
3696 BOOL
WineEngInit(void)
3698 HKEY hkey_font_cache
;
3702 /* update locale dependent font info in registry */
3705 if(!init_freetype()) return FALSE
;
3707 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3709 ERR("Failed to create font mutex\n");
3712 WaitForSingleObject(font_mutex
, INFINITE
);
3714 create_font_cache_key(&hkey_font_cache
, &disposition
);
3716 if(disposition
== REG_CREATED_NEW_KEY
)
3719 load_font_list_from_cache(hkey_font_cache
);
3721 RegCloseKey(hkey_font_cache
);
3723 reorder_font_list();
3730 if(disposition
== REG_CREATED_NEW_KEY
)
3731 update_reg_entries();
3733 init_system_links();
3735 ReleaseMutex(font_mutex
);
3740 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3743 TT_HoriHeader
*pHori
;
3747 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3748 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3750 if(height
== 0) height
= 16;
3752 /* Calc. height of EM square:
3754 * For +ve lfHeight we have
3755 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3756 * Re-arranging gives:
3757 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3759 * For -ve lfHeight we have
3761 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3762 * with il = winAscent + winDescent - units_per_em]
3767 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3768 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3769 pHori
->Ascender
- pHori
->Descender
);
3771 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3772 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3780 static struct font_mapping
*map_font_file( const char *name
)
3782 struct font_mapping
*mapping
;
3786 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3787 if (fstat( fd
, &st
) == -1) goto error
;
3789 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3791 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3793 mapping
->refcount
++;
3798 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3801 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3804 if (mapping
->data
== MAP_FAILED
)
3806 HeapFree( GetProcessHeap(), 0, mapping
);
3809 mapping
->refcount
= 1;
3810 mapping
->dev
= st
.st_dev
;
3811 mapping
->ino
= st
.st_ino
;
3812 mapping
->size
= st
.st_size
;
3813 list_add_tail( &mappings_list
, &mapping
->entry
);
3821 static void unmap_font_file( struct font_mapping
*mapping
)
3823 if (!--mapping
->refcount
)
3825 list_remove( &mapping
->entry
);
3826 munmap( mapping
->data
, mapping
->size
);
3827 HeapFree( GetProcessHeap(), 0, mapping
);
3831 static LONG
load_VDMX(GdiFont
*, LONG
);
3833 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3840 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3844 if (!(font
->mapping
= map_font_file( face
->file
)))
3846 WARN("failed to map %s\n", debugstr_a(face
->file
));
3849 data_ptr
= font
->mapping
->data
;
3850 data_size
= font
->mapping
->size
;
3854 data_ptr
= face
->font_data_ptr
;
3855 data_size
= face
->font_data_size
;
3858 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3860 ERR("FT_New_Face rets %d\n", err
);
3864 /* set it here, as load_VDMX needs it */
3865 font
->ft_face
= ft_face
;
3867 if(FT_IS_SCALABLE(ft_face
)) {
3868 /* load the VDMX table if we have one */
3869 font
->ppem
= load_VDMX(font
, height
);
3871 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3872 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3874 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3875 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3877 font
->ppem
= height
;
3878 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3879 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3885 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3887 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3888 a single face with the requested charset. The idea is to check if
3889 the selected font supports the current ANSI codepage, if it does
3890 return the corresponding charset, else return the first charset */
3893 int acp
= GetACP(), i
;
3897 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3899 const SYSTEM_LINKS
*font_link
;
3901 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
3902 return csi
.ciCharset
;
3904 font_link
= find_font_link(family_name
);
3905 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
3906 return csi
.ciCharset
;
3909 for(i
= 0; i
< 32; i
++) {
3911 if(face
->fs
.fsCsb
[0] & fs0
) {
3912 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3914 return csi
.ciCharset
;
3917 FIXME("TCI failing on %x\n", fs0
);
3921 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3922 face
->fs
.fsCsb
[0], face
->file
);
3924 return DEFAULT_CHARSET
;
3927 static GdiFont
*alloc_font(void)
3929 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3931 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3932 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3934 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3935 ret
->total_kern_pairs
= (DWORD
)-1;
3936 ret
->kern_pairs
= NULL
;
3937 list_init(&ret
->hfontlist
);
3938 list_init(&ret
->child_fonts
);
3942 static void free_font(GdiFont
*font
)
3944 struct list
*cursor
, *cursor2
;
3947 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3949 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3950 list_remove(cursor
);
3952 free_font(child
->font
);
3953 HeapFree(GetProcessHeap(), 0, child
);
3956 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3958 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3959 DeleteObject(hfontlist
->hfont
);
3960 list_remove(&hfontlist
->entry
);
3961 HeapFree(GetProcessHeap(), 0, hfontlist
);
3964 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3965 if (font
->mapping
) unmap_font_file( font
->mapping
);
3966 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3967 HeapFree(GetProcessHeap(), 0, font
->potm
);
3968 HeapFree(GetProcessHeap(), 0, font
->name
);
3969 for (i
= 0; i
< font
->gmsize
; i
++)
3970 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3971 HeapFree(GetProcessHeap(), 0, font
->gm
);
3972 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3973 HeapFree(GetProcessHeap(), 0, font
);
3977 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3979 FT_Face ft_face
= font
->ft_face
;
3983 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
3990 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
3992 /* make sure value of len is the value freetype says it needs */
3995 FT_ULong needed
= 0;
3996 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3997 if( !err
&& needed
< len
) len
= needed
;
3999 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4002 TRACE("Can't find table %c%c%c%c\n",
4003 /* bytes were reversed */
4004 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4005 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4011 /*************************************************************
4014 * load the vdmx entry for the specified height
4017 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4018 ( ( (FT_ULong)_x4 << 24 ) | \
4019 ( (FT_ULong)_x3 << 16 ) | \
4020 ( (FT_ULong)_x2 << 8 ) | \
4023 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4038 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4042 BYTE devXRatio
, devYRatio
;
4043 USHORT numRecs
, numRatios
;
4044 DWORD result
, offset
= -1;
4048 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4050 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4053 /* FIXME: need the real device aspect ratio */
4057 numRecs
= GET_BE_WORD(hdr
[1]);
4058 numRatios
= GET_BE_WORD(hdr
[2]);
4060 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4061 for(i
= 0; i
< numRatios
; i
++) {
4064 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4065 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4068 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4070 if((ratio
.xRatio
== 0 &&
4071 ratio
.yStartRatio
== 0 &&
4072 ratio
.yEndRatio
== 0) ||
4073 (devXRatio
== ratio
.xRatio
&&
4074 devYRatio
>= ratio
.yStartRatio
&&
4075 devYRatio
<= ratio
.yEndRatio
))
4077 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4078 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4079 offset
= GET_BE_WORD(tmp
);
4085 FIXME("No suitable ratio found\n");
4089 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4091 BYTE startsz
, endsz
;
4094 recs
= GET_BE_WORD(group
.recs
);
4095 startsz
= group
.startsz
;
4096 endsz
= group
.endsz
;
4098 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4100 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4101 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4102 if(result
== GDI_ERROR
) {
4103 FIXME("Failed to retrieve vTable\n");
4108 for(i
= 0; i
< recs
; i
++) {
4109 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4110 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4111 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4113 if(yMax
+ -yMin
== height
) {
4116 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4119 if(yMax
+ -yMin
> height
) {
4122 goto end
; /* failed */
4124 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4125 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4126 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4127 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4133 TRACE("ppem not found for height %d\n", height
);
4137 HeapFree(GetProcessHeap(), 0, vTable
);
4143 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4145 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4146 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4147 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4148 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4149 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4152 static void calc_hash(FONT_DESC
*pfd
)
4154 DWORD hash
= 0, *ptr
, two_chars
;
4158 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4160 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4162 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4164 pwc
= (WCHAR
*)&two_chars
;
4166 *pwc
= toupperW(*pwc
);
4168 *pwc
= toupperW(*pwc
);
4172 hash
^= !pfd
->can_use_bitmap
;
4177 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4182 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4186 fd
.can_use_bitmap
= can_use_bitmap
;
4189 /* try the child list */
4190 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
4191 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4192 if(!fontcmp(ret
, &fd
)) {
4193 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4194 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
4195 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4196 if(hflist
->hfont
== hfont
)
4202 /* try the in-use list */
4203 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
4204 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4205 if(!fontcmp(ret
, &fd
)) {
4206 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4207 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
4208 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4209 if(hflist
->hfont
== hfont
)
4212 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4213 hflist
->hfont
= hfont
;
4214 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4219 /* then the unused list */
4220 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4221 while(font_elem_ptr
) {
4222 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4223 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4224 if(!fontcmp(ret
, &fd
)) {
4225 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4226 assert(list_empty(&ret
->hfontlist
));
4227 TRACE("Found %p in unused list\n", ret
);
4228 list_remove(&ret
->entry
);
4229 list_add_head(&gdi_font_list
, &ret
->entry
);
4230 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4231 hflist
->hfont
= hfont
;
4232 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4239 static void add_to_cache(GdiFont
*font
)
4241 static DWORD cache_num
= 1;
4243 font
->cache_num
= cache_num
++;
4244 list_add_head(&gdi_font_list
, &font
->entry
);
4247 /*************************************************************
4248 * create_child_font_list
4250 static BOOL
create_child_font_list(GdiFont
*font
)
4253 SYSTEM_LINKS
*font_link
;
4254 CHILD_FONT
*font_link_entry
, *new_child
;
4258 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4259 font_name
= psub
? psub
->to
.name
: font
->name
;
4260 font_link
= find_font_link(font_name
);
4261 if (font_link
!= NULL
)
4263 TRACE("found entry in system list\n");
4264 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4266 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4267 new_child
->face
= font_link_entry
->face
;
4268 new_child
->font
= NULL
;
4269 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4270 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
4275 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4276 * Sans Serif. This is how asian windows get default fallbacks for fonts
4278 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4279 font
->charset
!= OEM_CHARSET
&&
4280 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4282 font_link
= find_font_link(szDefaultFallbackLink
);
4283 if (font_link
!= NULL
)
4285 TRACE("found entry in default fallback list\n");
4286 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4288 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4289 new_child
->face
= font_link_entry
->face
;
4290 new_child
->font
= NULL
;
4291 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4292 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
4301 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4303 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4305 if (pFT_Set_Charmap
)
4308 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4310 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4312 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4314 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4316 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4317 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4319 switch (ft_face
->charmaps
[i
]->platform_id
)
4322 cmap_def
= ft_face
->charmaps
[i
];
4324 case 0: /* Apple Unicode */
4325 cmap0
= ft_face
->charmaps
[i
];
4327 case 1: /* Macintosh */
4328 cmap1
= ft_face
->charmaps
[i
];
4331 cmap2
= ft_face
->charmaps
[i
];
4333 case 3: /* Microsoft */
4334 cmap3
= ft_face
->charmaps
[i
];
4339 if (cmap3
) /* prefer Microsoft cmap table */
4340 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4342 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4344 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4346 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4348 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4350 return ft_err
== FT_Err_Ok
;
4353 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4357 /*************************************************************
4360 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4361 LPCWSTR output
, const DEVMODEW
*devmode
)
4363 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4365 if (!physdev
) return FALSE
;
4366 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4371 /*************************************************************
4374 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4376 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4377 HeapFree( GetProcessHeap(), 0, physdev
);
4382 /*************************************************************
4383 * freetype_SelectFont
4385 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
4387 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4389 Face
*face
, *best
, *best_bitmap
;
4390 Family
*family
, *last_resort_family
;
4391 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4392 INT height
, width
= 0;
4393 unsigned int score
= 0, new_score
;
4394 signed int diff
= 0, newdiff
;
4395 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4400 FontSubst
*psub
= NULL
;
4401 DC
*dc
= get_dc_ptr( dev
->hdc
);
4402 const SYSTEM_LINKS
*font_link
;
4404 if (!hfont
) /* notification that the font has been changed by another driver */
4407 physdev
->font
= NULL
;
4408 release_dc_ptr( dc
);
4412 GetObjectW( hfont
, sizeof(lf
), &lf
);
4413 lf
.lfWidth
= abs(lf
.lfWidth
);
4415 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4417 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4418 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4419 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4422 if(dc
->GraphicsMode
== GM_ADVANCED
)
4424 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4425 /* Try to avoid not necessary glyph transformations */
4426 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4428 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4429 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4430 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4435 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4436 font scaling abilities. */
4437 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4438 dcmat
.eM21
= dcmat
.eM12
= 0;
4439 if (dc
->vport2WorldValid
)
4441 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4442 lf
.lfOrientation
= -lf
.lfOrientation
;
4443 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4444 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4448 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4449 dcmat
.eM21
, dcmat
.eM22
);
4452 EnterCriticalSection( &freetype_cs
);
4454 /* check the cache first */
4455 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4456 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4460 if(list_empty(&font_list
)) /* No fonts installed */
4462 TRACE("No fonts installed\n");
4466 TRACE("not in cache\n");
4469 ret
->font_desc
.matrix
= dcmat
;
4470 ret
->font_desc
.lf
= lf
;
4471 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4472 calc_hash(&ret
->font_desc
);
4473 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4474 hflist
->hfont
= hfont
;
4475 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4477 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4478 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4479 original value lfCharSet. Note this is a special case for
4480 Symbol and doesn't happen at least for "Wingdings*" */
4482 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4483 lf
.lfCharSet
= SYMBOL_CHARSET
;
4485 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4486 switch(lf
.lfCharSet
) {
4487 case DEFAULT_CHARSET
:
4488 csi
.fs
.fsCsb
[0] = 0;
4491 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4492 csi
.fs
.fsCsb
[0] = 0;
4498 if(lf
.lfFaceName
[0] != '\0') {
4499 CHILD_FONT
*font_link_entry
;
4500 LPWSTR FaceName
= lf
.lfFaceName
;
4502 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4505 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4506 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4507 if (psub
->to
.charset
!= -1)
4508 lf
.lfCharSet
= psub
->to
.charset
;
4511 /* We want a match on name and charset or just name if
4512 charset was DEFAULT_CHARSET. If the latter then
4513 we fixup the returned charset later in get_nearest_charset
4514 where we'll either use the charset of the current ansi codepage
4515 or if that's unavailable the first charset that the font supports.
4517 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4518 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4519 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4520 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4522 font_link
= find_font_link(family
->FamilyName
);
4523 face_list
= get_face_list_from_family(family
);
4524 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4525 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4526 if (!(face
->scalable
|| can_use_bitmap
))
4528 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4530 if (font_link
!= NULL
&&
4531 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4533 if (!csi
.fs
.fsCsb
[0])
4539 /* Search by full face name. */
4540 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4541 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4542 face_list
= get_face_list_from_family(family
);
4543 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4544 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4545 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4546 (face
->scalable
|| can_use_bitmap
))
4548 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4550 font_link
= find_font_link(family
->FamilyName
);
4551 if (font_link
!= NULL
&&
4552 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4559 * Try check the SystemLink list first for a replacement font.
4560 * We may find good replacements there.
4562 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4564 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4565 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4567 TRACE("found entry in system list\n");
4568 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4570 const SYSTEM_LINKS
*links
;
4572 face
= font_link_entry
->face
;
4573 if (!(face
->scalable
|| can_use_bitmap
))
4575 family
= face
->family
;
4576 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4578 links
= find_font_link(family
->FamilyName
);
4579 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4586 psub
= NULL
; /* substitution is no more relevant */
4588 /* If requested charset was DEFAULT_CHARSET then try using charset
4589 corresponding to the current ansi codepage */
4590 if (!csi
.fs
.fsCsb
[0])
4593 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4594 FIXME("TCI failed on codepage %d\n", acp
);
4595 csi
.fs
.fsCsb
[0] = 0;
4597 lf
.lfCharSet
= csi
.ciCharset
;
4600 want_vertical
= (lf
.lfFaceName
[0] == '@');
4602 /* Face families are in the top 4 bits of lfPitchAndFamily,
4603 so mask with 0xF0 before testing */
4605 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4606 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4607 strcpyW(lf
.lfFaceName
, defFixed
);
4608 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4609 strcpyW(lf
.lfFaceName
, defSerif
);
4610 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4611 strcpyW(lf
.lfFaceName
, defSans
);
4613 strcpyW(lf
.lfFaceName
, defSans
);
4614 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4615 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4616 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4617 font_link
= find_font_link(family
->FamilyName
);
4618 face_list
= get_face_list_from_family(family
);
4619 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4620 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4621 if (!(face
->scalable
|| can_use_bitmap
))
4623 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4625 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4631 last_resort_family
= NULL
;
4632 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4633 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4634 font_link
= find_font_link(family
->FamilyName
);
4635 face_list
= get_face_list_from_family(family
);
4636 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4637 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4638 if(face
->vertical
== want_vertical
&&
4639 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4640 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4643 if(can_use_bitmap
&& !last_resort_family
)
4644 last_resort_family
= family
;
4649 if(last_resort_family
) {
4650 family
= last_resort_family
;
4651 csi
.fs
.fsCsb
[0] = 0;
4655 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4656 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4657 face_list
= get_face_list_from_family(family
);
4658 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4659 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4660 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4661 csi
.fs
.fsCsb
[0] = 0;
4662 WARN("just using first face for now\n");
4665 if(can_use_bitmap
&& !last_resort_family
)
4666 last_resort_family
= family
;
4669 if(!last_resort_family
) {
4670 FIXME("can't find a single appropriate font - bailing\n");
4676 WARN("could only find a bitmap font - this will probably look awful!\n");
4677 family
= last_resort_family
;
4678 csi
.fs
.fsCsb
[0] = 0;
4681 it
= lf
.lfItalic
? 1 : 0;
4682 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4684 height
= lf
.lfHeight
;
4686 face
= best
= best_bitmap
= NULL
;
4687 font_link
= find_font_link(family
->FamilyName
);
4688 face_list
= get_face_list_from_family(family
);
4689 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4691 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4692 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4697 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4698 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4699 new_score
= (italic
^ it
) + (bold
^ bd
);
4700 if(!best
|| new_score
<= score
)
4702 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4703 italic
, bold
, it
, bd
);
4706 if(best
->scalable
&& score
== 0) break;
4710 newdiff
= height
- (signed int)(best
->size
.height
);
4712 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4713 if(!best_bitmap
|| new_score
< score
||
4714 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4716 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4719 if(score
== 0 && diff
== 0) break;
4726 face
= best
->scalable
? best
: best_bitmap
;
4727 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4728 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4731 height
= lf
.lfHeight
;
4735 if(csi
.fs
.fsCsb
[0]) {
4736 ret
->charset
= lf
.lfCharSet
;
4737 ret
->codepage
= csi
.ciACP
;
4740 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4742 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4743 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4745 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4747 if(!face
->scalable
) {
4748 /* Windows uses integer scaling factors for bitmap fonts */
4749 INT scale
, scaled_height
;
4750 GdiFont
*cachedfont
;
4752 /* FIXME: rotation of bitmap fonts is ignored */
4753 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4755 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4756 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4757 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4758 /* As we changed the matrix, we need to search the cache for the font again,
4759 * otherwise we might explode the cache. */
4760 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4761 TRACE("Found cached font after non-scalable matrix rescale!\n");
4766 calc_hash(&ret
->font_desc
);
4768 if (height
!= 0) height
= diff
;
4769 height
+= face
->size
.height
;
4771 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4772 scaled_height
= scale
* face
->size
.height
;
4773 /* Only jump to the next height if the difference <= 25% original height */
4774 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4775 /* The jump between unscaled and doubled is delayed by 1 */
4776 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4777 ret
->scale_y
= scale
;
4779 width
= face
->size
.x_ppem
>> 6;
4780 height
= face
->size
.y_ppem
>> 6;
4784 TRACE("font scale y: %f\n", ret
->scale_y
);
4786 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4795 ret
->ntmFlags
= face
->ntmFlags
;
4797 if (ret
->charset
== SYMBOL_CHARSET
&&
4798 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4801 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4805 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4808 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4809 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4810 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4811 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4812 create_child_font_list(ret
);
4814 if (face
->vertical
) /* We need to try to load the GSUB table */
4816 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4817 if (length
!= GDI_ERROR
)
4819 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4820 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4821 TRACE("Loaded GSUB table of %i bytes\n",length
);
4825 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4832 physdev
->font
= ret
;
4834 LeaveCriticalSection( &freetype_cs
);
4835 release_dc_ptr( dc
);
4836 return ret
? hfont
: 0;
4839 static void dump_gdi_font_list(void)
4842 struct list
*elem_ptr
;
4844 TRACE("---------- gdiFont Cache ----------\n");
4845 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4846 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4847 TRACE("gdiFont=%p %s %d\n",
4848 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4851 TRACE("---------- Unused gdiFont Cache ----------\n");
4852 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4853 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4854 TRACE("gdiFont=%p %s %d\n",
4855 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4858 TRACE("---------- Child gdiFont Cache ----------\n");
4859 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4860 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4861 TRACE("gdiFont=%p %s %d\n",
4862 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4866 /*************************************************************
4867 * WineEngDestroyFontInstance
4869 * free the gdiFont associated with this handle
4872 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4877 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4881 EnterCriticalSection( &freetype_cs
);
4883 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4885 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4886 while(hfontlist_elem_ptr
) {
4887 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4888 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4889 if(hflist
->hfont
== handle
) {
4890 TRACE("removing child font %p from child list\n", gdiFont
);
4891 list_remove(&gdiFont
->entry
);
4892 LeaveCriticalSection( &freetype_cs
);
4898 TRACE("destroying hfont=%p\n", handle
);
4900 dump_gdi_font_list();
4902 font_elem_ptr
= list_head(&gdi_font_list
);
4903 while(font_elem_ptr
) {
4904 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4905 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4907 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4908 while(hfontlist_elem_ptr
) {
4909 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4910 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4911 if(hflist
->hfont
== handle
) {
4912 list_remove(&hflist
->entry
);
4913 HeapFree(GetProcessHeap(), 0, hflist
);
4917 if(list_empty(&gdiFont
->hfontlist
)) {
4918 TRACE("Moving to Unused list\n");
4919 list_remove(&gdiFont
->entry
);
4920 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4925 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4926 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4927 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4928 while(font_elem_ptr
) {
4929 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4930 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4931 TRACE("freeing %p\n", gdiFont
);
4932 list_remove(&gdiFont
->entry
);
4935 LeaveCriticalSection( &freetype_cs
);
4939 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4946 id
+= IDS_FIRST_SCRIPT
;
4947 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4948 if (!rsrc
) return 0;
4949 hMem
= LoadResource( gdi32_module
, rsrc
);
4950 if (!hMem
) return 0;
4952 p
= LockResource( hMem
);
4954 while (id
--) p
+= *p
+ 1;
4956 i
= min(LF_FACESIZE
- 1, *p
);
4957 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4963 /***************************************************
4964 * create_enum_charset_list
4966 * This function creates charset enumeration list because in DEFAULT_CHARSET
4967 * case, the ANSI codepage's charset takes precedence over other charsets.
4968 * This function works as a filter other than DEFAULT_CHARSET case.
4970 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4975 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4976 csi
.fs
.fsCsb
[0] != 0) {
4977 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4978 list
->element
[n
].charset
= csi
.ciCharset
;
4979 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4982 else { /* charset is DEFAULT_CHARSET or invalid. */
4985 /* Set the current codepage's charset as the first element. */
4987 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
4988 csi
.fs
.fsCsb
[0] != 0) {
4989 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4990 list
->element
[n
].charset
= csi
.ciCharset
;
4991 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
4995 /* Fill out left elements. */
4996 for (i
= 0; i
< 32; i
++) {
4998 fs
.fsCsb
[0] = 1L << i
;
5000 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
5001 continue; /* skip, already added. */
5002 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5003 continue; /* skip, this is an invalid fsCsb bit. */
5005 list
->element
[n
].mask
= fs
.fsCsb
[0];
5006 list
->element
[n
].charset
= csi
.ciCharset
;
5007 load_script_name( i
, list
->element
[n
].name
);
5016 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
5017 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5022 if (face
->cached_enum_data
)
5025 *pelf
= face
->cached_enum_data
->elf
;
5026 *pntm
= face
->cached_enum_data
->ntm
;
5027 *ptype
= face
->cached_enum_data
->type
;
5031 font
= alloc_font();
5033 if(face
->scalable
) {
5034 height
= -2048; /* 2048 is the most common em size */
5037 height
= face
->size
.y_ppem
>> 6;
5038 width
= face
->size
.x_ppem
>> 6;
5040 font
->scale_y
= 1.0;
5042 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5048 font
->name
= strdupW(face
->family
->FamilyName
);
5049 font
->ntmFlags
= face
->ntmFlags
;
5051 if (get_outline_text_metrics(font
))
5053 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5055 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5057 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5058 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5060 lstrcpynW(pelf
->elfFullName
,
5061 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
5063 lstrcpynW(pelf
->elfStyle
,
5064 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5069 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5071 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5073 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
5075 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5077 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
5078 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5081 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5082 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5083 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5084 pntm
->ntmFontSig
= face
->fs
;
5086 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5088 pelf
->elfLogFont
.lfEscapement
= 0;
5089 pelf
->elfLogFont
.lfOrientation
= 0;
5090 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5091 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5092 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5093 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5094 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5095 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5096 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5097 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5098 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5099 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5100 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5103 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5104 *ptype
|= TRUETYPE_FONTTYPE
;
5105 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5106 *ptype
|= DEVICE_FONTTYPE
;
5107 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5108 *ptype
|= RASTER_FONTTYPE
;
5110 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5111 if (face
->cached_enum_data
)
5113 face
->cached_enum_data
->elf
= *pelf
;
5114 face
->cached_enum_data
->ntm
= *pntm
;
5115 face
->cached_enum_data
->type
= *ptype
;
5121 static void create_full_name(WCHAR
*full_name
, const WCHAR
*family_name
, const WCHAR
*style_name
)
5123 static const WCHAR spaceW
[] = { ' ', 0 };
5125 strcpyW(full_name
, family_name
);
5126 strcatW(full_name
, spaceW
);
5127 strcatW(full_name
, style_name
);
5130 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5132 const struct list
*face_list
, *face_elem_ptr
;
5134 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5136 face_list
= get_face_list_from_family(family
);
5137 LIST_FOR_EACH(face_elem_ptr
, face_list
)
5139 WCHAR full_family_name
[LF_FULLFACESIZE
];
5140 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5142 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
5144 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5145 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
5149 create_full_name(full_family_name
, family
->FamilyName
, face
->StyleName
);
5150 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
5156 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5158 WCHAR full_family_name
[LF_FULLFACESIZE
];
5160 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5162 if (strlenW(family_name
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
5164 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5165 debugstr_w(family_name
), debugstr_w(face
->StyleName
));
5169 create_full_name(full_family_name
, family_name
, face
->StyleName
);
5170 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
5173 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5174 FONTENUMPROCW proc
, LPARAM lparam
)
5177 NEWTEXTMETRICEXW ntm
;
5181 GetEnumStructs(face
, &elf
, &ntm
, &type
);
5182 for(i
= 0; i
< list
->total
; i
++) {
5183 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5184 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5185 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
5186 i
= list
->total
; /* break out of loop after enumeration */
5187 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
5190 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5191 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5192 if (!elf
.elfScript
[0])
5193 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5195 /* Font Replacement */
5196 if (family
!= face
->family
)
5198 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5199 create_full_name(elf
.elfFullName
, family
->FamilyName
, face
->StyleName
);
5201 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5202 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5203 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5204 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5205 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5206 ntm
.ntmTm
.ntmFlags
);
5207 /* release section before callback (FIXME) */
5208 LeaveCriticalSection( &freetype_cs
);
5209 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5210 EnterCriticalSection( &freetype_cs
);
5215 /*************************************************************
5216 * freetype_EnumFonts
5218 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5222 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
5224 struct enum_charset_list enum_charsets
;
5228 lf
.lfCharSet
= DEFAULT_CHARSET
;
5229 lf
.lfPitchAndFamily
= 0;
5230 lf
.lfFaceName
[0] = 0;
5234 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5236 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5239 EnterCriticalSection( &freetype_cs
);
5240 if(plf
->lfFaceName
[0]) {
5242 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5245 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5246 debugstr_w(psub
->to
.name
));
5248 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5252 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
5253 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
5254 if(family_matches(family
, plf
)) {
5255 face_list
= get_face_list_from_family(family
);
5256 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
5257 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5258 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5259 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5264 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
5265 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
5266 face_list
= get_face_list_from_family(family
);
5267 face_elem_ptr
= list_head(face_list
);
5268 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5269 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5272 LeaveCriticalSection( &freetype_cs
);
5276 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5278 pt
->x
.value
= vec
->x
>> 6;
5279 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5280 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5281 pt
->y
.value
= vec
->y
>> 6;
5282 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5283 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5287 /***************************************************
5288 * According to the MSDN documentation on WideCharToMultiByte,
5289 * certain codepages cannot set the default_used parameter.
5290 * This returns TRUE if the codepage can set that parameter, false else
5291 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5293 static BOOL
codepage_sets_default_used(UINT codepage
)
5307 * GSUB Table handling functions
5310 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5312 const GSUB_CoverageFormat1
* cf1
;
5316 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5318 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5320 TRACE("Coverage Format 1, %i glyphs\n",count
);
5321 for (i
= 0; i
< count
; i
++)
5322 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5326 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5328 const GSUB_CoverageFormat2
* cf2
;
5331 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5333 count
= GET_BE_WORD(cf2
->RangeCount
);
5334 TRACE("Coverage Format 2, %i ranges\n",count
);
5335 for (i
= 0; i
< count
; i
++)
5337 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5339 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5340 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5342 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5343 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5349 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5354 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5356 const GSUB_ScriptList
*script
;
5357 const GSUB_Script
*deflt
= NULL
;
5359 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5361 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5362 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5364 const GSUB_Script
*scr
;
5367 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5368 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5370 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5372 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5378 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5382 const GSUB_LangSys
*Lang
;
5384 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5386 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5388 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5389 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5391 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5394 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5397 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5403 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5406 const GSUB_FeatureList
*feature
;
5407 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5409 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5410 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5412 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5413 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5415 const GSUB_Feature
*feat
;
5416 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5423 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5427 const GSUB_LookupList
*lookup
;
5428 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5430 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5431 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5433 const GSUB_LookupTable
*look
;
5434 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5435 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5436 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5437 if (GET_BE_WORD(look
->LookupType
) != 1)
5438 FIXME("We only handle SubType 1\n");
5443 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5445 const GSUB_SingleSubstFormat1
*ssf1
;
5446 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5447 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5448 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5450 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5451 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5452 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5454 TRACE(" Glyph 0x%x ->",glyph
);
5455 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5456 TRACE(" 0x%x\n",glyph
);
5461 const GSUB_SingleSubstFormat2
*ssf2
;
5465 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5466 offset
= GET_BE_WORD(ssf1
->Coverage
);
5467 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5468 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5469 TRACE(" Coverage index %i\n",index
);
5472 TRACE(" Glyph is 0x%x ->",glyph
);
5473 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5474 TRACE("0x%x\n",glyph
);
5483 static const char* get_opentype_script(const GdiFont
*font
)
5486 * I am not sure if this is the correct way to generate our script tag
5489 switch (font
->charset
)
5491 case ANSI_CHARSET
: return "latn";
5492 case BALTIC_CHARSET
: return "latn"; /* ?? */
5493 case CHINESEBIG5_CHARSET
: return "hani";
5494 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5495 case GB2312_CHARSET
: return "hani";
5496 case GREEK_CHARSET
: return "grek";
5497 case HANGUL_CHARSET
: return "hang";
5498 case RUSSIAN_CHARSET
: return "cyrl";
5499 case SHIFTJIS_CHARSET
: return "kana";
5500 case TURKISH_CHARSET
: return "latn"; /* ?? */
5501 case VIETNAMESE_CHARSET
: return "latn";
5502 case JOHAB_CHARSET
: return "latn"; /* ?? */
5503 case ARABIC_CHARSET
: return "arab";
5504 case HEBREW_CHARSET
: return "hebr";
5505 case THAI_CHARSET
: return "thai";
5506 default: return "latn";
5510 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5512 const GSUB_Header
*header
;
5513 const GSUB_Script
*script
;
5514 const GSUB_LangSys
*language
;
5515 const GSUB_Feature
*feature
;
5517 if (!font
->GSUB_Table
)
5520 header
= font
->GSUB_Table
;
5522 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5525 TRACE("Script not found\n");
5528 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5531 TRACE("Language not found\n");
5534 feature
= GSUB_get_feature(header
, language
, "vrt2");
5536 feature
= GSUB_get_feature(header
, language
, "vert");
5539 TRACE("vrt2/vert feature not found\n");
5542 return GSUB_apply_feature(header
, feature
, glyph
);
5545 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5549 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5550 WCHAR wc
= (WCHAR
)glyph
;
5552 BOOL
*default_used_pointer
;
5555 default_used_pointer
= NULL
;
5556 default_used
= FALSE
;
5557 if (codepage_sets_default_used(font
->codepage
))
5558 default_used_pointer
= &default_used
;
5559 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5562 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5563 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5567 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5569 if (glyph
< 0x100) glyph
+= 0xf000;
5570 /* there is a number of old pre-Unicode "broken" TTFs, which
5571 do have symbols at U+00XX instead of U+f0XX */
5572 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5573 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5575 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5580 /*************************************************************
5581 * freetype_GetGlyphIndices
5583 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5585 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5588 BOOL got_default
= FALSE
;
5592 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5593 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5596 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5598 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5603 EnterCriticalSection( &freetype_cs
);
5605 for(i
= 0; i
< count
; i
++)
5607 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5612 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5614 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5615 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5620 get_text_metrics(physdev
->font
, &textm
);
5621 default_char
= textm
.tmDefaultChar
;
5625 pgi
[i
] = default_char
;
5628 LeaveCriticalSection( &freetype_cs
);
5632 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5634 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5635 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5638 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5640 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5641 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5644 static inline BYTE
get_max_level( UINT format
)
5648 case GGO_GRAY2_BITMAP
: return 4;
5649 case GGO_GRAY4_BITMAP
: return 16;
5650 case GGO_GRAY8_BITMAP
: return 64;
5655 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5657 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5658 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5661 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5662 FT_Face ft_face
= incoming_font
->ft_face
;
5663 GdiFont
*font
= incoming_font
;
5664 FT_UInt glyph_index
;
5665 DWORD width
, height
, pitch
, needed
= 0;
5666 FT_Bitmap ft_bitmap
;
5668 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5670 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5671 double widthRatio
= 1.0;
5672 FT_Matrix transMat
= identityMat
;
5673 FT_Matrix transMatUnrotated
;
5674 BOOL needsTransform
= FALSE
;
5675 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5676 UINT original_index
;
5678 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5679 buflen
, buf
, lpmat
);
5681 TRACE("font transform %f %f %f %f\n",
5682 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5683 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5685 if(format
& GGO_GLYPH_INDEX
) {
5686 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5687 original_index
= glyph
;
5688 format
&= ~GGO_GLYPH_INDEX
;
5690 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5691 ft_face
= font
->ft_face
;
5692 original_index
= glyph_index
;
5695 if(format
& GGO_UNHINTED
) {
5696 load_flags
|= FT_LOAD_NO_HINTING
;
5697 format
&= ~GGO_UNHINTED
;
5700 /* tategaki never appears to happen to lower glyph index */
5701 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5704 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5705 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5706 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5707 font
->gmsize
* sizeof(GM
*));
5709 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5710 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5712 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5713 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5714 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5715 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5716 return 1; /* FIXME */
5720 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5721 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5723 /* Scaling factor */
5728 get_text_metrics(font
, &tm
);
5730 widthRatio
= (double)font
->aveWidth
;
5731 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5734 widthRatio
= font
->scale_y
;
5736 /* Scaling transform */
5737 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5740 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5743 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5745 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5746 needsTransform
= TRUE
;
5749 /* Slant transform */
5750 if (font
->fake_italic
) {
5753 slantMat
.xx
= (1 << 16);
5754 slantMat
.xy
= ((1 << 16) >> 2);
5756 slantMat
.yy
= (1 << 16);
5757 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5758 needsTransform
= TRUE
;
5761 /* Rotation transform */
5762 transMatUnrotated
= transMat
;
5763 if(font
->orientation
&& !tategaki
) {
5764 FT_Matrix rotationMat
;
5766 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5767 pFT_Vector_Unit(&vecAngle
, angle
);
5768 rotationMat
.xx
= vecAngle
.x
;
5769 rotationMat
.xy
= -vecAngle
.y
;
5770 rotationMat
.yx
= -rotationMat
.xy
;
5771 rotationMat
.yy
= rotationMat
.xx
;
5773 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5774 needsTransform
= TRUE
;
5777 /* World transform */
5778 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5781 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5782 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5783 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5784 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5785 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5786 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5787 needsTransform
= TRUE
;
5790 /* Extra transformation specified by caller */
5791 if (!is_identity_MAT2(lpmat
))
5794 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5795 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5796 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5797 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5798 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5799 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5800 needsTransform
= TRUE
;
5803 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5804 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5805 format
== GGO_GRAY8_BITMAP
))
5807 load_flags
|= FT_LOAD_NO_BITMAP
;
5810 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5813 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5817 if(!needsTransform
) {
5818 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5819 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5820 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5822 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5823 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5824 ft_face
->glyph
->metrics
.height
) & -64;
5825 lpgm
->gmCellIncX
= adv
;
5826 lpgm
->gmCellIncY
= 0;
5833 for(xc
= 0; xc
< 2; xc
++) {
5834 for(yc
= 0; yc
< 2; yc
++) {
5835 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5836 xc
* ft_face
->glyph
->metrics
.width
);
5837 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5838 yc
* ft_face
->glyph
->metrics
.height
;
5839 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5840 pFT_Vector_Transform(&vec
, &transMat
);
5841 if(xc
== 0 && yc
== 0) {
5842 left
= right
= vec
.x
;
5843 top
= bottom
= vec
.y
;
5845 if(vec
.x
< left
) left
= vec
.x
;
5846 else if(vec
.x
> right
) right
= vec
.x
;
5847 if(vec
.y
< bottom
) bottom
= vec
.y
;
5848 else if(vec
.y
> top
) top
= vec
.y
;
5853 right
= (right
+ 63) & -64;
5854 bottom
= bottom
& -64;
5855 top
= (top
+ 63) & -64;
5857 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5858 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5860 pFT_Vector_Transform(&vec
, &transMat
);
5861 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5862 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5864 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5866 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5867 adv
= (vec
.x
+63) >> 6;
5871 bbx
= (right
- left
) >> 6;
5872 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5873 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5874 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5875 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5877 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5878 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5879 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5881 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5882 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5884 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5885 FONT_GM(font
,original_index
)->adv
= adv
;
5886 FONT_GM(font
,original_index
)->lsb
= lsb
;
5887 FONT_GM(font
,original_index
)->bbx
= bbx
;
5888 FONT_GM(font
,original_index
)->init
= TRUE
;
5891 if(format
== GGO_METRICS
)
5893 return 1; /* FIXME */
5896 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5897 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5899 TRACE("loaded a bitmap\n");
5905 width
= lpgm
->gmBlackBoxX
;
5906 height
= lpgm
->gmBlackBoxY
;
5907 pitch
= ((width
+ 31) >> 5) << 2;
5908 needed
= pitch
* height
;
5910 if(!buf
|| !buflen
) break;
5912 switch(ft_face
->glyph
->format
) {
5913 case ft_glyph_format_bitmap
:
5915 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5916 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5917 INT h
= ft_face
->glyph
->bitmap
.rows
;
5919 memcpy(dst
, src
, w
);
5920 src
+= ft_face
->glyph
->bitmap
.pitch
;
5926 case ft_glyph_format_outline
:
5927 ft_bitmap
.width
= width
;
5928 ft_bitmap
.rows
= height
;
5929 ft_bitmap
.pitch
= pitch
;
5930 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5931 ft_bitmap
.buffer
= buf
;
5934 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5936 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5938 /* Note: FreeType will only set 'black' bits for us. */
5939 memset(buf
, 0, needed
);
5940 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5944 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5949 case GGO_GRAY2_BITMAP
:
5950 case GGO_GRAY4_BITMAP
:
5951 case GGO_GRAY8_BITMAP
:
5952 case WINE_GGO_GRAY16_BITMAP
:
5954 unsigned int max_level
, row
, col
;
5957 width
= lpgm
->gmBlackBoxX
;
5958 height
= lpgm
->gmBlackBoxY
;
5959 pitch
= (width
+ 3) / 4 * 4;
5960 needed
= pitch
* height
;
5962 if(!buf
|| !buflen
) break;
5964 max_level
= get_max_level( format
);
5966 switch(ft_face
->glyph
->format
) {
5967 case ft_glyph_format_bitmap
:
5969 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5970 INT h
= ft_face
->glyph
->bitmap
.rows
;
5972 memset( buf
, 0, needed
);
5974 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5975 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5976 src
+= ft_face
->glyph
->bitmap
.pitch
;
5981 case ft_glyph_format_outline
:
5983 ft_bitmap
.width
= width
;
5984 ft_bitmap
.rows
= height
;
5985 ft_bitmap
.pitch
= pitch
;
5986 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
5987 ft_bitmap
.buffer
= buf
;
5990 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5992 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5994 memset(ft_bitmap
.buffer
, 0, buflen
);
5996 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5998 if (max_level
!= 255)
6000 for (row
= 0, start
= buf
; row
< height
; row
++)
6002 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6003 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
6011 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6017 case WINE_GGO_HRGB_BITMAP
:
6018 case WINE_GGO_HBGR_BITMAP
:
6019 case WINE_GGO_VRGB_BITMAP
:
6020 case WINE_GGO_VBGR_BITMAP
:
6021 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6023 switch (ft_face
->glyph
->format
)
6025 case FT_GLYPH_FORMAT_BITMAP
:
6030 width
= lpgm
->gmBlackBoxX
;
6031 height
= lpgm
->gmBlackBoxY
;
6033 needed
= pitch
* height
;
6035 if (!buf
|| !buflen
) break;
6037 memset(buf
, 0, buflen
);
6039 src
= ft_face
->glyph
->bitmap
.buffer
;
6040 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6042 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6045 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6047 if ( src
[x
/ 8] & masks
[x
% 8] )
6048 ((unsigned int *)dst
)[x
] = ~0u;
6057 case FT_GLYPH_FORMAT_OUTLINE
:
6061 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6062 INT x_shift
, y_shift
;
6064 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6065 FT_Render_Mode render_mode
=
6066 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6067 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6069 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6071 if ( render_mode
== FT_RENDER_MODE_LCD
)
6073 lpgm
->gmBlackBoxX
+= 2;
6074 lpgm
->gmptGlyphOrigin
.x
-= 1;
6078 lpgm
->gmBlackBoxY
+= 2;
6079 lpgm
->gmptGlyphOrigin
.y
+= 1;
6083 width
= lpgm
->gmBlackBoxX
;
6084 height
= lpgm
->gmBlackBoxY
;
6086 needed
= pitch
* height
;
6088 if (!buf
|| !buflen
) break;
6090 memset(buf
, 0, buflen
);
6092 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6094 if ( needsTransform
)
6095 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6097 if ( pFT_Library_SetLcdFilter
)
6098 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6099 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6101 src
= ft_face
->glyph
->bitmap
.buffer
;
6102 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6103 src_width
= ft_face
->glyph
->bitmap
.width
;
6104 src_height
= ft_face
->glyph
->bitmap
.rows
;
6106 if ( render_mode
== FT_RENDER_MODE_LCD
)
6114 rgb_interval
= src_pitch
;
6119 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6120 if ( x_shift
< 0 ) x_shift
= 0;
6121 if ( x_shift
+ (src_width
/ hmul
) > width
)
6122 x_shift
= width
- (src_width
/ hmul
);
6124 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6125 if ( y_shift
< 0 ) y_shift
= 0;
6126 if ( y_shift
+ (src_height
/ vmul
) > height
)
6127 y_shift
= height
- (src_height
/ vmul
);
6129 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
6130 while ( src_height
)
6132 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
6136 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6137 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6138 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6139 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6143 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6144 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6145 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6146 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6149 src
+= src_pitch
* vmul
;
6158 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6170 int contour
, point
= 0, first_pt
;
6171 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6172 TTPOLYGONHEADER
*pph
;
6174 DWORD pph_start
, cpfx
, type
;
6176 if(buflen
== 0) buf
= NULL
;
6178 if (needsTransform
&& buf
) {
6179 pFT_Outline_Transform(outline
, &transMat
);
6182 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6184 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6187 pph
->dwType
= TT_POLYGON_TYPE
;
6188 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6190 needed
+= sizeof(*pph
);
6192 while(point
<= outline
->contours
[contour
]) {
6193 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6194 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6195 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6199 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6202 } while(point
<= outline
->contours
[contour
] &&
6203 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6204 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6205 /* At the end of a contour Windows adds the start point, but
6207 if(point
> outline
->contours
[contour
] &&
6208 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6210 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6212 } else if(point
<= outline
->contours
[contour
] &&
6213 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6214 /* add closing pt for bezier */
6216 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6224 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6227 pph
->cb
= needed
- pph_start
;
6233 /* Convert the quadratic Beziers to cubic Beziers.
6234 The parametric eqn for a cubic Bezier is, from PLRM:
6235 r(t) = at^3 + bt^2 + ct + r0
6236 with the control points:
6241 A quadratic Bezier has the form:
6242 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6244 So equating powers of t leads to:
6245 r1 = 2/3 p1 + 1/3 p0
6246 r2 = 2/3 p1 + 1/3 p2
6247 and of course r0 = p0, r3 = p2
6250 int contour
, point
= 0, first_pt
;
6251 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6252 TTPOLYGONHEADER
*pph
;
6254 DWORD pph_start
, cpfx
, type
;
6255 FT_Vector cubic_control
[4];
6256 if(buflen
== 0) buf
= NULL
;
6258 if (needsTransform
&& buf
) {
6259 pFT_Outline_Transform(outline
, &transMat
);
6262 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6264 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6267 pph
->dwType
= TT_POLYGON_TYPE
;
6268 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6270 needed
+= sizeof(*pph
);
6272 while(point
<= outline
->contours
[contour
]) {
6273 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6274 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6275 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6278 if(type
== TT_PRIM_LINE
) {
6280 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6284 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6287 /* FIXME: Possible optimization in endpoint calculation
6288 if there are two consecutive curves */
6289 cubic_control
[0] = outline
->points
[point
-1];
6290 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6291 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6292 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6293 cubic_control
[0].x
>>= 1;
6294 cubic_control
[0].y
>>= 1;
6296 if(point
+1 > outline
->contours
[contour
])
6297 cubic_control
[3] = outline
->points
[first_pt
];
6299 cubic_control
[3] = outline
->points
[point
+1];
6300 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6301 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6302 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6303 cubic_control
[3].x
>>= 1;
6304 cubic_control
[3].y
>>= 1;
6307 /* r1 = 1/3 p0 + 2/3 p1
6308 r2 = 1/3 p2 + 2/3 p1 */
6309 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6310 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6311 cubic_control
[2] = cubic_control
[1];
6312 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6313 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6314 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6315 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6317 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6318 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6319 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6324 } while(point
<= outline
->contours
[contour
] &&
6325 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6326 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6327 /* At the end of a contour Windows adds the start point,
6328 but only for Beziers and we've already done that.
6330 if(point
<= outline
->contours
[contour
] &&
6331 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6332 /* This is the closing pt of a bezier, but we've already
6333 added it, so just inc point and carry on */
6340 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6343 pph
->cb
= needed
- pph_start
;
6349 FIXME("Unsupported format %d\n", format
);
6355 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6357 FT_Face ft_face
= font
->ft_face
;
6358 FT_WinFNT_HeaderRec winfnt_header
;
6359 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6360 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6361 font
->potm
->otmSize
= size
;
6363 #define TM font->potm->otmTextMetrics
6364 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6366 TM
.tmHeight
= winfnt_header
.pixel_height
;
6367 TM
.tmAscent
= winfnt_header
.ascent
;
6368 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6369 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6370 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6371 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6372 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6373 TM
.tmWeight
= winfnt_header
.weight
;
6375 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6376 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6377 TM
.tmFirstChar
= winfnt_header
.first_char
;
6378 TM
.tmLastChar
= winfnt_header
.last_char
;
6379 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6380 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6381 TM
.tmItalic
= winfnt_header
.italic
;
6382 TM
.tmUnderlined
= font
->underline
;
6383 TM
.tmStruckOut
= font
->strikeout
;
6384 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6385 TM
.tmCharSet
= winfnt_header
.charset
;
6389 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6390 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6391 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6392 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6393 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6394 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6395 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6396 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6398 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6399 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6401 TM
.tmLastChar
= 255;
6402 TM
.tmDefaultChar
= 32;
6403 TM
.tmBreakChar
= 32;
6404 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6405 TM
.tmUnderlined
= font
->underline
;
6406 TM
.tmStruckOut
= font
->strikeout
;
6407 /* NB inverted meaning of TMPF_FIXED_PITCH */
6408 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6409 TM
.tmCharSet
= font
->charset
;
6417 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6419 double scale_x
, scale_y
;
6423 scale_x
= (double)font
->aveWidth
;
6424 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6427 scale_x
= font
->scale_y
;
6429 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6430 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6432 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6433 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6435 SCALE_Y(ptm
->tmHeight
);
6436 SCALE_Y(ptm
->tmAscent
);
6437 SCALE_Y(ptm
->tmDescent
);
6438 SCALE_Y(ptm
->tmInternalLeading
);
6439 SCALE_Y(ptm
->tmExternalLeading
);
6440 SCALE_Y(ptm
->tmOverhang
);
6442 SCALE_X(ptm
->tmAveCharWidth
);
6443 SCALE_X(ptm
->tmMaxCharWidth
);
6449 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6451 double scale_x
, scale_y
;
6455 scale_x
= (double)font
->aveWidth
;
6456 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6459 scale_x
= font
->scale_y
;
6461 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6462 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6464 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6466 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6467 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6469 SCALE_Y(potm
->otmAscent
);
6470 SCALE_Y(potm
->otmDescent
);
6471 SCALE_Y(potm
->otmLineGap
);
6472 SCALE_Y(potm
->otmsCapEmHeight
);
6473 SCALE_Y(potm
->otmsXHeight
);
6474 SCALE_Y(potm
->otmrcFontBox
.top
);
6475 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6476 SCALE_X(potm
->otmrcFontBox
.left
);
6477 SCALE_X(potm
->otmrcFontBox
.right
);
6478 SCALE_Y(potm
->otmMacAscent
);
6479 SCALE_Y(potm
->otmMacDescent
);
6480 SCALE_Y(potm
->otmMacLineGap
);
6481 SCALE_X(potm
->otmptSubscriptSize
.x
);
6482 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6483 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6484 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6485 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6486 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6487 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6488 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6489 SCALE_Y(potm
->otmsStrikeoutSize
);
6490 SCALE_Y(potm
->otmsStrikeoutPosition
);
6491 SCALE_Y(potm
->otmsUnderscoreSize
);
6492 SCALE_Y(potm
->otmsUnderscorePosition
);
6498 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6502 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6504 /* Make sure that the font has sane width/height ratio */
6507 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6509 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6514 *ptm
= font
->potm
->otmTextMetrics
;
6515 scale_font_metrics(font
, ptm
);
6519 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6523 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6525 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6531 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6534 FT_Face ft_face
= font
->ft_face
;
6535 UINT needed
, lenfam
, lensty
;
6537 TT_HoriHeader
*pHori
;
6538 TT_Postscript
*pPost
;
6539 FT_Fixed x_scale
, y_scale
;
6540 WCHAR
*family_nameW
, *style_nameW
;
6541 static const WCHAR spaceW
[] = {' ', '\0'};
6543 INT ascent
, descent
;
6545 TRACE("font=%p\n", font
);
6547 if(!FT_IS_SCALABLE(ft_face
))
6550 needed
= sizeof(*font
->potm
);
6552 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6553 family_nameW
= strdupW(font
->name
);
6555 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6557 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6558 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6559 style_nameW
, lensty
/sizeof(WCHAR
));
6561 /* These names should be read from the TT name table */
6563 /* length of otmpFamilyName */
6566 /* length of otmpFaceName */
6567 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6568 needed
+= lenfam
; /* just the family name */
6570 needed
+= lenfam
+ lensty
; /* family + " " + style */
6573 /* length of otmpStyleName */
6576 /* length of otmpFullName */
6577 needed
+= lenfam
+ lensty
;
6580 x_scale
= ft_face
->size
->metrics
.x_scale
;
6581 y_scale
= ft_face
->size
->metrics
.y_scale
;
6583 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6585 FIXME("Can't find OS/2 table - not TT font?\n");
6589 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6591 FIXME("Can't find HHEA table - not TT font?\n");
6595 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6597 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",
6598 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6599 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6600 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6601 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6602 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6604 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6605 font
->potm
->otmSize
= needed
;
6607 #define TM font->potm->otmTextMetrics
6609 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6610 ascent
= pHori
->Ascender
;
6611 descent
= -pHori
->Descender
;
6613 ascent
= pOS2
->usWinAscent
;
6614 descent
= pOS2
->usWinDescent
;
6618 TM
.tmAscent
= font
->yMax
;
6619 TM
.tmDescent
= -font
->yMin
;
6620 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6622 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6623 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6624 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6625 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6628 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6631 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6633 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6634 ((ascent
+ descent
) -
6635 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6637 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6638 if (TM
.tmAveCharWidth
== 0) {
6639 TM
.tmAveCharWidth
= 1;
6641 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6642 TM
.tmWeight
= FW_REGULAR
;
6643 if (font
->fake_bold
)
6644 TM
.tmWeight
= FW_BOLD
;
6647 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6649 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6650 TM
.tmWeight
= pOS2
->usWeightClass
;
6652 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6653 TM
.tmWeight
= pOS2
->usWeightClass
;
6656 TM
.tmDigitizedAspectX
= 300;
6657 TM
.tmDigitizedAspectY
= 300;
6658 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6659 * symbol range to 0 - f0ff
6662 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6667 case 1257: /* Baltic */
6668 TM
.tmLastChar
= 0xf8fd;
6671 TM
.tmLastChar
= 0xf0ff;
6673 TM
.tmBreakChar
= 0x20;
6674 TM
.tmDefaultChar
= 0x1f;
6678 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6679 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6681 if(pOS2
->usFirstCharIndex
<= 1)
6682 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6683 else if (pOS2
->usFirstCharIndex
> 0xff)
6684 TM
.tmBreakChar
= 0x20;
6686 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6687 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6689 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6690 TM
.tmUnderlined
= font
->underline
;
6691 TM
.tmStruckOut
= font
->strikeout
;
6693 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6694 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6695 (pOS2
->version
== 0xFFFFU
||
6696 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6697 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6699 TM
.tmPitchAndFamily
= 0;
6701 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6703 case PAN_FAMILY_SCRIPT
:
6704 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6707 case PAN_FAMILY_DECORATIVE
:
6708 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6713 case PAN_FAMILY_TEXT_DISPLAY
:
6714 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6715 /* which is clearly not what the panose spec says. */
6717 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6718 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6719 TM
.tmPitchAndFamily
= FF_MODERN
;
6722 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6727 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6730 case PAN_SERIF_COVE
:
6731 case PAN_SERIF_OBTUSE_COVE
:
6732 case PAN_SERIF_SQUARE_COVE
:
6733 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6734 case PAN_SERIF_SQUARE
:
6735 case PAN_SERIF_THIN
:
6736 case PAN_SERIF_BONE
:
6737 case PAN_SERIF_EXAGGERATED
:
6738 case PAN_SERIF_TRIANGLE
:
6739 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6742 case PAN_SERIF_NORMAL_SANS
:
6743 case PAN_SERIF_OBTUSE_SANS
:
6744 case PAN_SERIF_PERP_SANS
:
6745 case PAN_SERIF_FLARED
:
6746 case PAN_SERIF_ROUNDED
:
6747 TM
.tmPitchAndFamily
|= FF_SWISS
;
6754 if(FT_IS_SCALABLE(ft_face
))
6755 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6757 if(FT_IS_SFNT(ft_face
))
6759 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6760 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6762 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6765 TM
.tmCharSet
= font
->charset
;
6767 font
->potm
->otmFiller
= 0;
6768 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6769 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6770 font
->potm
->otmfsType
= pOS2
->fsType
;
6771 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6772 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6773 font
->potm
->otmItalicAngle
= 0; /* POST table */
6774 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6775 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6776 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6777 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6778 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6779 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6780 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6781 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6782 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6783 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6784 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6785 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6786 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6787 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6788 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6789 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6790 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6791 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6792 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6793 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6794 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6795 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6796 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6797 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6799 font
->potm
->otmsUnderscoreSize
= 0;
6800 font
->potm
->otmsUnderscorePosition
= 0;
6802 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6803 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6807 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6808 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6809 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6810 strcpyW((WCHAR
*)cp
, family_nameW
);
6812 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6813 strcpyW((WCHAR
*)cp
, style_nameW
);
6815 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6816 strcpyW((WCHAR
*)cp
, family_nameW
);
6817 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6818 strcatW((WCHAR
*)cp
, spaceW
);
6819 strcatW((WCHAR
*)cp
, style_nameW
);
6820 cp
+= lenfam
+ lensty
;
6823 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6824 strcpyW((WCHAR
*)cp
, family_nameW
);
6825 strcatW((WCHAR
*)cp
, spaceW
);
6826 strcatW((WCHAR
*)cp
, style_nameW
);
6830 HeapFree(GetProcessHeap(), 0, style_nameW
);
6831 HeapFree(GetProcessHeap(), 0, family_nameW
);
6835 /*************************************************************
6836 * freetype_GetGlyphOutline
6838 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6839 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6841 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6846 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6847 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6851 EnterCriticalSection( &freetype_cs
);
6852 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6853 LeaveCriticalSection( &freetype_cs
);
6857 /*************************************************************
6858 * freetype_GetTextMetrics
6860 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6862 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6867 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6868 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6872 EnterCriticalSection( &freetype_cs
);
6873 ret
= get_text_metrics( physdev
->font
, metrics
);
6874 LeaveCriticalSection( &freetype_cs
);
6878 /*************************************************************
6879 * freetype_GetOutlineTextMetrics
6881 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6883 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6888 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6889 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6892 TRACE("font=%p\n", physdev
->font
);
6894 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6897 EnterCriticalSection( &freetype_cs
);
6899 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6901 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6903 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6904 scale_outline_font_metrics(physdev
->font
, potm
);
6906 ret
= physdev
->font
->potm
->otmSize
;
6908 LeaveCriticalSection( &freetype_cs
);
6912 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6914 HFONTLIST
*hfontlist
;
6915 child
->font
= alloc_font();
6916 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6917 if(!child
->font
->ft_face
)
6919 free_font(child
->font
);
6924 child
->font
->font_desc
= font
->font_desc
;
6925 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6926 child
->font
->orientation
= font
->orientation
;
6927 child
->font
->scale_y
= font
->scale_y
;
6928 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6929 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6930 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6931 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6932 child
->font
->base_font
= font
;
6933 list_add_head(&child_font_list
, &child
->font
->entry
);
6934 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6938 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6941 CHILD_FONT
*child_font
;
6944 font
= font
->base_font
;
6946 *linked_font
= font
;
6948 if((*glyph
= get_glyph_index(font
, c
)))
6950 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6954 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6956 if(!child_font
->font
)
6957 if(!load_child_font(font
, child_font
))
6960 if(!child_font
->font
->ft_face
)
6962 g
= get_glyph_index(child_font
->font
, c
);
6963 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6967 *linked_font
= child_font
->font
;
6974 /*************************************************************
6975 * freetype_GetCharWidth
6977 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
6979 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
6982 FT_UInt glyph_index
;
6983 GdiFont
*linked_font
;
6984 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6988 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
6989 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
6992 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
6995 EnterCriticalSection( &freetype_cs
);
6996 for(c
= firstChar
; c
<= lastChar
; c
++) {
6997 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
6998 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
6999 &gm
, 0, NULL
, &identity
);
7000 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
7002 LeaveCriticalSection( &freetype_cs
);
7006 /*************************************************************
7007 * freetype_GetCharABCWidths
7009 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7011 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7014 FT_UInt glyph_index
;
7015 GdiFont
*linked_font
;
7016 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7020 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7021 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7024 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7027 EnterCriticalSection( &freetype_cs
);
7029 for(c
= firstChar
; c
<= lastChar
; c
++) {
7030 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
7031 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7032 &gm
, 0, NULL
, &identity
);
7033 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
7034 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
7035 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
7036 FONT_GM(linked_font
,glyph_index
)->bbx
;
7038 LeaveCriticalSection( &freetype_cs
);
7042 /*************************************************************
7043 * freetype_GetCharABCWidthsI
7045 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7047 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7050 FT_UInt glyph_index
;
7051 GdiFont
*linked_font
;
7052 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7056 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7057 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7060 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7064 EnterCriticalSection( &freetype_cs
);
7066 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
7068 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
7069 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7070 &gm
, 0, NULL
, &identity
);
7071 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
7072 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
7073 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
7074 - FONT_GM(linked_font
,c
)->bbx
;
7077 for(c
= 0; c
< count
; c
++) {
7078 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7079 &gm
, 0, NULL
, &identity
);
7080 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
7081 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
7082 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
7083 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
7086 LeaveCriticalSection( &freetype_cs
);
7090 /*************************************************************
7091 * freetype_GetTextExtentExPoint
7093 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
7094 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
7096 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7101 FT_UInt glyph_index
;
7102 GdiFont
*linked_font
;
7103 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7107 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7108 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
7111 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
7114 EnterCriticalSection( &freetype_cs
);
7117 get_text_metrics( physdev
->font
, &tm
);
7118 size
->cy
= tm
.tmHeight
;
7120 for(idx
= 0; idx
< count
; idx
++) {
7121 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
7122 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7123 &gm
, 0, NULL
, &identity
);
7124 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
7126 if (! pnfit
|| ext
<= max_ext
) {
7136 LeaveCriticalSection( &freetype_cs
);
7137 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
7141 /*************************************************************
7142 * freetype_GetTextExtentExPointI
7144 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
7145 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
7147 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7152 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7156 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7157 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
7160 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
7163 EnterCriticalSection( &freetype_cs
);
7166 get_text_metrics(physdev
->font
, &tm
);
7167 size
->cy
= tm
.tmHeight
;
7169 for(idx
= 0; idx
< count
; idx
++) {
7170 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
7171 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
7173 if (! pnfit
|| ext
<= max_ext
) {
7183 LeaveCriticalSection( &freetype_cs
);
7184 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
7188 /*************************************************************
7189 * freetype_GetFontData
7191 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7193 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7197 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7198 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7201 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7202 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7203 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7205 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7208 /*************************************************************
7209 * freetype_GetTextFace
7211 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7214 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7218 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7219 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7222 n
= strlenW(physdev
->font
->name
) + 1;
7225 lstrcpynW(str
, physdev
->font
->name
, count
);
7231 /*************************************************************
7232 * freetype_GetTextCharsetInfo
7234 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7236 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7240 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7241 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7243 if (fs
) *fs
= physdev
->font
->fs
;
7244 return physdev
->font
->charset
;
7247 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7249 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
7250 struct list
*first_hfont
;
7254 EnterCriticalSection( &freetype_cs
);
7255 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
7256 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
7257 if(font
== linked_font
)
7258 *new_hfont
= dc
->hFont
;
7261 first_hfont
= list_head(&linked_font
->hfontlist
);
7262 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
7264 LeaveCriticalSection( &freetype_cs
);
7268 /* Retrieve a list of supported Unicode ranges for a given font.
7269 * Can be called with NULL gs to calculate the buffer size. Returns
7270 * the number of ranges found.
7272 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7274 DWORD num_ranges
= 0;
7276 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7279 FT_ULong char_code
, char_code_prev
;
7282 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7284 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7285 face
->num_glyphs
, glyph_code
, char_code
);
7287 if (!glyph_code
) return 0;
7291 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7292 gs
->ranges
[0].cGlyphs
= 0;
7293 gs
->cGlyphsSupported
= 0;
7299 if (char_code
< char_code_prev
)
7301 ERR("expected increasing char code from FT_Get_Next_Char\n");
7304 if (char_code
- char_code_prev
> 1)
7309 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7310 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7311 gs
->cGlyphsSupported
++;
7316 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7317 gs
->cGlyphsSupported
++;
7319 char_code_prev
= char_code
;
7320 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7324 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7329 /*************************************************************
7330 * freetype_GetFontUnicodeRanges
7332 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7334 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7335 DWORD size
, num_ranges
;
7339 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7340 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7343 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7344 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7347 glyphset
->cbThis
= size
;
7348 glyphset
->cRanges
= num_ranges
;
7349 glyphset
->flAccel
= 0;
7354 /*************************************************************
7355 * freetype_FontIsLinked
7357 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7359 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7364 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7365 return dev
->funcs
->pFontIsLinked( dev
);
7369 EnterCriticalSection( &freetype_cs
);
7370 ret
= !list_empty(&physdev
->font
->child_fonts
);
7371 LeaveCriticalSection( &freetype_cs
);
7375 static BOOL
is_hinting_enabled(void)
7377 /* Use the >= 2.2.0 function if available */
7378 if(pFT_Get_TrueType_Engine_Type
)
7380 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
7381 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
7383 #ifdef FT_DRIVER_HAS_HINTER
7388 /* otherwise if we've been compiled with < 2.2.0 headers
7389 use the internal macro */
7390 mod
= pFT_Get_Module(library
, "truetype");
7391 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
7399 static BOOL
is_subpixel_rendering_enabled( void )
7401 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7402 return pFT_Library_SetLcdFilter
&&
7403 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
7409 /*************************************************************************
7410 * GetRasterizerCaps (GDI32.@)
7412 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7414 static int hinting
= -1;
7415 static int subpixel
= -1;
7419 hinting
= is_hinting_enabled();
7420 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
7423 if ( subpixel
== -1 )
7425 subpixel
= is_subpixel_rendering_enabled();
7426 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
7429 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7430 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
7432 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
7433 lprs
->nLanguageID
= 0;
7437 /*************************************************************
7438 * freetype_GdiRealizationInfo
7440 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7442 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7443 realization_info_t
*info
= ptr
;
7447 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7448 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7451 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7454 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7457 info
->cache_num
= physdev
->font
->cache_num
;
7458 info
->unknown2
= -1;
7462 /*************************************************************************
7463 * Kerning support for TrueType fonts
7465 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7467 struct TT_kern_table
7473 struct TT_kern_subtable
7482 USHORT horizontal
: 1;
7484 USHORT cross_stream
: 1;
7485 USHORT override
: 1;
7486 USHORT reserved1
: 4;
7492 struct TT_format0_kern_subtable
7496 USHORT entrySelector
;
7507 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7508 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7509 const USHORT
*glyph_to_char
,
7510 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7513 const struct TT_kern_pair
*tt_kern_pair
;
7515 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7517 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7519 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7520 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7521 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7523 if (!kern_pair
|| !cPairs
)
7526 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7528 nPairs
= min(nPairs
, cPairs
);
7530 for (i
= 0; i
< nPairs
; i
++)
7532 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7533 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7534 /* this algorithm appears to better match what Windows does */
7535 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7536 if (kern_pair
->iKernAmount
< 0)
7538 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7539 kern_pair
->iKernAmount
-= font
->ppem
;
7541 else if (kern_pair
->iKernAmount
> 0)
7543 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7544 kern_pair
->iKernAmount
+= font
->ppem
;
7546 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7548 TRACE("left %u right %u value %d\n",
7549 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7553 TRACE("copied %u entries\n", nPairs
);
7557 /*************************************************************
7558 * freetype_GetKerningPairs
7560 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7564 const struct TT_kern_table
*tt_kern_table
;
7565 const struct TT_kern_subtable
*tt_kern_subtable
;
7567 USHORT
*glyph_to_char
;
7569 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7571 if (!(font
= physdev
->font
))
7573 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7574 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7578 EnterCriticalSection( &freetype_cs
);
7579 if (font
->total_kern_pairs
!= (DWORD
)-1)
7581 if (cPairs
&& kern_pair
)
7583 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7584 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7586 else cPairs
= font
->total_kern_pairs
;
7588 LeaveCriticalSection( &freetype_cs
);
7592 font
->total_kern_pairs
= 0;
7594 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7596 if (length
== GDI_ERROR
)
7598 TRACE("no kerning data in the font\n");
7599 LeaveCriticalSection( &freetype_cs
);
7603 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7606 WARN("Out of memory\n");
7607 LeaveCriticalSection( &freetype_cs
);
7611 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7613 /* build a glyph index to char code map */
7614 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7617 WARN("Out of memory allocating a glyph index to char code map\n");
7618 HeapFree(GetProcessHeap(), 0, buf
);
7619 LeaveCriticalSection( &freetype_cs
);
7623 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7629 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7631 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7632 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7636 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7638 /* FIXME: This doesn't match what Windows does: it does some fancy
7639 * things with duplicate glyph index to char code mappings, while
7640 * we just avoid overriding existing entries.
7642 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7643 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7645 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7652 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7653 for (n
= 0; n
<= 65535; n
++)
7654 glyph_to_char
[n
] = (USHORT
)n
;
7657 tt_kern_table
= buf
;
7658 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7659 TRACE("version %u, nTables %u\n",
7660 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7662 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7664 for (i
= 0; i
< nTables
; i
++)
7666 struct TT_kern_subtable tt_kern_subtable_copy
;
7668 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7669 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7670 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7672 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7673 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7674 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7676 /* According to the TrueType specification this is the only format
7677 * that will be properly interpreted by Windows and OS/2
7679 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7681 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7683 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7684 glyph_to_char
, NULL
, 0);
7685 font
->total_kern_pairs
+= new_chunk
;
7687 if (!font
->kern_pairs
)
7688 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7689 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7691 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7692 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7694 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7695 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7698 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7700 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7703 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7704 HeapFree(GetProcessHeap(), 0, buf
);
7706 if (cPairs
&& kern_pair
)
7708 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7709 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7711 else cPairs
= font
->total_kern_pairs
;
7713 LeaveCriticalSection( &freetype_cs
);
7717 static const struct gdi_dc_funcs freetype_funcs
=
7719 NULL
, /* pAbortDoc */
7720 NULL
, /* pAbortPath */
7721 NULL
, /* pAlphaBlend */
7722 NULL
, /* pAngleArc */
7725 NULL
, /* pBeginPath */
7726 NULL
, /* pBlendImage */
7727 NULL
, /* pChoosePixelFormat */
7729 NULL
, /* pCloseFigure */
7730 NULL
, /* pCopyBitmap */
7731 NULL
, /* pCreateBitmap */
7732 NULL
, /* pCreateCompatibleDC */
7733 freetype_CreateDC
, /* pCreateDC */
7734 NULL
, /* pDeleteBitmap */
7735 freetype_DeleteDC
, /* pDeleteDC */
7736 NULL
, /* pDeleteObject */
7737 NULL
, /* pDescribePixelFormat */
7738 NULL
, /* pDeviceCapabilities */
7739 NULL
, /* pEllipse */
7741 NULL
, /* pEndPage */
7742 NULL
, /* pEndPath */
7743 freetype_EnumFonts
, /* pEnumFonts */
7744 NULL
, /* pEnumICMProfiles */
7745 NULL
, /* pExcludeClipRect */
7746 NULL
, /* pExtDeviceMode */
7747 NULL
, /* pExtEscape */
7748 NULL
, /* pExtFloodFill */
7749 NULL
, /* pExtSelectClipRgn */
7750 NULL
, /* pExtTextOut */
7751 NULL
, /* pFillPath */
7752 NULL
, /* pFillRgn */
7753 NULL
, /* pFlattenPath */
7754 freetype_FontIsLinked
, /* pFontIsLinked */
7755 NULL
, /* pFrameRgn */
7756 NULL
, /* pGdiComment */
7757 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7758 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7759 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7760 freetype_GetCharWidth
, /* pGetCharWidth */
7761 NULL
, /* pGetDeviceCaps */
7762 NULL
, /* pGetDeviceGammaRamp */
7763 freetype_GetFontData
, /* pGetFontData */
7764 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7765 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7766 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7767 NULL
, /* pGetICMProfile */
7768 NULL
, /* pGetImage */
7769 freetype_GetKerningPairs
, /* pGetKerningPairs */
7770 NULL
, /* pGetNearestColor */
7771 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7772 NULL
, /* pGetPixel */
7773 NULL
, /* pGetPixelFormat */
7774 NULL
, /* pGetSystemPaletteEntries */
7775 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7776 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7777 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7778 freetype_GetTextFace
, /* pGetTextFace */
7779 freetype_GetTextMetrics
, /* pGetTextMetrics */
7780 NULL
, /* pGradientFill */
7781 NULL
, /* pIntersectClipRect */
7782 NULL
, /* pInvertRgn */
7784 NULL
, /* pModifyWorldTransform */
7786 NULL
, /* pOffsetClipRgn */
7787 NULL
, /* pOffsetViewportOrg */
7788 NULL
, /* pOffsetWindowOrg */
7789 NULL
, /* pPaintRgn */
7792 NULL
, /* pPolyBezier */
7793 NULL
, /* pPolyBezierTo */
7794 NULL
, /* pPolyDraw */
7795 NULL
, /* pPolyPolygon */
7796 NULL
, /* pPolyPolyline */
7797 NULL
, /* pPolygon */
7798 NULL
, /* pPolyline */
7799 NULL
, /* pPolylineTo */
7800 NULL
, /* pPutImage */
7801 NULL
, /* pRealizeDefaultPalette */
7802 NULL
, /* pRealizePalette */
7803 NULL
, /* pRectangle */
7804 NULL
, /* pResetDC */
7805 NULL
, /* pRestoreDC */
7806 NULL
, /* pRoundRect */
7808 NULL
, /* pScaleViewportExt */
7809 NULL
, /* pScaleWindowExt */
7810 NULL
, /* pSelectBitmap */
7811 NULL
, /* pSelectBrush */
7812 NULL
, /* pSelectClipPath */
7813 freetype_SelectFont
, /* pSelectFont */
7814 NULL
, /* pSelectPalette */
7815 NULL
, /* pSelectPen */
7816 NULL
, /* pSetArcDirection */
7817 NULL
, /* pSetBkColor */
7818 NULL
, /* pSetBkMode */
7819 NULL
, /* pSetDCBrushColor */
7820 NULL
, /* pSetDCPenColor */
7821 NULL
, /* pSetDIBColorTable */
7822 NULL
, /* pSetDIBitsToDevice */
7823 NULL
, /* pSetDeviceClipping */
7824 NULL
, /* pSetDeviceGammaRamp */
7825 NULL
, /* pSetLayout */
7826 NULL
, /* pSetMapMode */
7827 NULL
, /* pSetMapperFlags */
7828 NULL
, /* pSetPixel */
7829 NULL
, /* pSetPixelFormat */
7830 NULL
, /* pSetPolyFillMode */
7831 NULL
, /* pSetROP2 */
7832 NULL
, /* pSetRelAbs */
7833 NULL
, /* pSetStretchBltMode */
7834 NULL
, /* pSetTextAlign */
7835 NULL
, /* pSetTextCharacterExtra */
7836 NULL
, /* pSetTextColor */
7837 NULL
, /* pSetTextJustification */
7838 NULL
, /* pSetViewportExt */
7839 NULL
, /* pSetViewportOrg */
7840 NULL
, /* pSetWindowExt */
7841 NULL
, /* pSetWindowOrg */
7842 NULL
, /* pSetWorldTransform */
7843 NULL
, /* pStartDoc */
7844 NULL
, /* pStartPage */
7845 NULL
, /* pStretchBlt */
7846 NULL
, /* pStretchDIBits */
7847 NULL
, /* pStrokeAndFillPath */
7848 NULL
, /* pStrokePath */
7849 NULL
, /* pSwapBuffers */
7850 NULL
, /* pUnrealizePalette */
7851 NULL
, /* pWidenPath */
7852 /* OpenGL not supported */
7855 #else /* HAVE_FREETYPE */
7857 /*************************************************************************/
7859 BOOL
WineEngInit(void)
7863 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7868 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7870 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7874 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7876 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7880 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7882 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7886 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
7887 LPCWSTR font_file
, LPCWSTR font_path
)
7893 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7898 /*************************************************************************
7899 * GetRasterizerCaps (GDI32.@)
7901 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7903 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7905 lprs
->nLanguageID
= 0;
7909 #endif /* HAVE_FREETYPE */