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
;
345 UINT ntmCellHeight
, ntmAvgWidth
;
354 const WCHAR
*font_name
;
359 struct enum_charset_element
{
362 WCHAR name
[LF_FACESIZE
];
365 struct enum_charset_list
{
367 struct enum_charset_element element
[32];
370 #define GM_BLOCK_SIZE 128
371 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
373 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
374 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
375 #define UNUSED_CACHE_SIZE 10
376 static struct list child_font_list
= LIST_INIT(child_font_list
);
377 static struct list system_links
= LIST_INIT(system_links
);
379 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
381 static struct list font_list
= LIST_INIT(font_list
);
383 struct freetype_physdev
385 struct gdi_physdev dev
;
389 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
391 return (struct freetype_physdev
*)dev
;
394 static const struct gdi_dc_funcs freetype_funcs
;
396 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
397 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
398 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
400 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
401 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
402 'W','i','n','d','o','w','s','\\',
403 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
404 'F','o','n','t','s','\0'};
406 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
407 'W','i','n','d','o','w','s',' ','N','T','\\',
408 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
409 'F','o','n','t','s','\0'};
411 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
412 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
413 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
414 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
416 static const WCHAR
* const SystemFontValues
[] = {
423 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
424 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
426 /* Interesting and well-known (frequently-assumed!) font names */
427 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
428 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 };
429 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
430 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
431 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
432 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
433 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
434 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
436 static const WCHAR arial
[] = {'A','r','i','a','l',0};
437 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
438 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};
439 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};
440 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
441 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
442 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
443 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
444 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
445 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
447 static const WCHAR
*default_serif_list
[] =
451 bitstream_vera_serif
,
455 static const WCHAR
*default_fixed_list
[] =
459 bitstream_vera_sans_mono
,
463 static const WCHAR
*default_sans_list
[] =
476 typedef struct tagFontSubst
{
482 /* Registry font cache key and value names */
483 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
484 'F','o','n','t','s',0};
485 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
486 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
487 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
488 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
489 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_vertical_value
[] = {'V','e','r','t','i','c','a','l',0};
491 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 static struct list mappings_list
= LIST_INIT( mappings_list
);
513 static CRITICAL_SECTION freetype_cs
;
514 static CRITICAL_SECTION_DEBUG critsect_debug
=
517 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
518 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback
= FALSE
;
527 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
528 static BOOL
get_outline_text_metrics(GdiFont
*font
);
529 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
531 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
547 * FIXEDFON.FON FixedSys
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
589 GSUB_ScriptRecord ScriptRecord
[1];
595 } GSUB_LangSysRecord
;
600 GSUB_LangSysRecord LangSysRecord
[1];
604 WORD LookupOrder
; /* Reserved */
605 WORD ReqFeatureIndex
;
607 WORD FeatureIndex
[1];
613 } GSUB_FeatureRecord
;
617 GSUB_FeatureRecord FeatureRecord
[1];
621 WORD FeatureParams
; /* Reserved */
623 WORD LookupListIndex
[1];
642 } GSUB_CoverageFormat1
;
647 WORD StartCoverageIndex
;
653 GSUB_RangeRecord RangeRecord
[1];
654 } GSUB_CoverageFormat2
;
657 WORD SubstFormat
; /* = 1 */
660 } GSUB_SingleSubstFormat1
;
663 WORD SubstFormat
; /* = 2 */
667 }GSUB_SingleSubstFormat2
;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
674 static char cached_path
[MAX_PATH
];
675 static const char *wine
= "/Wine", *fonts
= "/Fonts";
677 if(*cached_path
) return cached_path
;
679 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
682 WARN("can't create cached data folder\n");
685 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
688 WARN("can't create cached data path\n");
692 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
694 ERR("Could not create full path\n");
698 strcat(cached_path
, wine
);
700 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
702 WARN("Couldn't mkdir %s\n", cached_path
);
706 strcat(cached_path
, fonts
);
707 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
709 WARN("Couldn't mkdir %s\n", cached_path
);
716 /******************************************************************
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path
)
734 const char *filename
;
738 unsigned int size
, max_size
;
741 TRACE("path %s\n", path
);
743 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
746 WARN("failed to get ref\n");
750 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
757 TRACE("unable to open resource fork\n");
764 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
767 CloseResFile(res_ref
);
771 out_dir
= find_cache_dir();
773 filename
= strrchr(path
, '/');
774 if(!filename
) filename
= path
;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
785 unsigned short *num_faces_ptr
, num_faces
, face
;
788 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
790 fond
= Get1IndResource(fond_res
, idx
);
792 TRACE("got fond resource %d\n", idx
);
795 fam_rec
= *(FamRec
**)fond
;
796 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
797 num_faces
= GET_BE_WORD(*num_faces_ptr
);
799 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
800 TRACE("num faces %04x\n", num_faces
);
801 for(face
= 0; face
< num_faces
; face
++, assoc
++)
804 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
805 unsigned short size
, font_id
;
808 size
= GET_BE_WORD(assoc
->fontSize
);
809 font_id
= GET_BE_WORD(assoc
->fontID
);
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
816 TRACE("trying to load sfnt id %04x\n", font_id
);
817 sfnt
= GetResource(sfnt_res
, font_id
);
820 TRACE("can't get sfnt resource %04x\n", font_id
);
824 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
829 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
831 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
832 if(fd
!= -1 || errno
== EEXIST
)
836 unsigned char *sfnt_data
;
839 sfnt_data
= *(unsigned char**)sfnt
;
840 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
844 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
847 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
849 ret
.array
[ret
.size
++] = output
;
853 WARN("unable to create %s\n", output
);
854 HeapFree(GetProcessHeap(), 0, output
);
857 ReleaseResource(sfnt
);
860 ReleaseResource(fond
);
863 CloseResFile(res_ref
);
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL
is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed
FT_FixedFromFloat(double f
)
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
889 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
893 static const struct list
*get_face_list_from_family(const Family
*family
)
895 if (!list_empty(&family
->faces
))
896 return &family
->faces
;
898 return family
->replacement
;
901 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
906 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
907 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
909 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
912 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
914 const struct list
*face_list
;
915 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
917 face_list
= get_face_list_from_family(family
);
918 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
922 file
= strrchr(face
->file
, '/');
927 if(!strcasecmp(file
, file_nameA
))
929 HeapFree(GetProcessHeap(), 0, file_nameA
);
934 HeapFree(GetProcessHeap(), 0, file_nameA
);
938 static Family
*find_family_from_name(const WCHAR
*name
)
942 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
944 if(!strcmpiW(family
->FamilyName
, name
))
951 static Family
*find_family_from_any_name(const WCHAR
*name
)
955 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
957 if(!strcmpiW(family
->FamilyName
, name
))
959 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
966 static void DumpSubstList(void)
970 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
972 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
974 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
976 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
977 debugstr_w(psub
->to
.name
));
982 static LPWSTR
strdupW(LPCWSTR p
)
985 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
986 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
991 static LPSTR
strdupA(LPCSTR p
)
994 DWORD len
= (strlen(p
) + 1);
995 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1000 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1005 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1007 if(!strcmpiW(element
->from
.name
, from_name
) &&
1008 (element
->from
.charset
== from_charset
||
1009 element
->from
.charset
== -1))
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1020 FontSubst
*from_exist
, *to_exist
;
1022 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1024 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1026 list_remove(&from_exist
->entry
);
1027 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
1028 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
1029 HeapFree(GetProcessHeap(), 0, from_exist
);
1035 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1039 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1040 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1043 list_add_tail(subst_list
, &subst
->entry
);
1048 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1049 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1050 HeapFree(GetProcessHeap(), 0, subst
);
1054 static WCHAR
*towstr(UINT cp
, const char *str
)
1059 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1060 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1061 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1065 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1067 CHAR
*p
= strrchr(str
, ',');
1071 nc
->charset
= strtol(p
+1, NULL
, 10);
1074 nc
->name
= towstr(CP_ACP
, str
);
1077 static void LoadSubstList(void)
1081 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey
) == ERROR_SUCCESS
) {
1089 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1090 &valuelen
, &datalen
, NULL
, NULL
);
1092 valuelen
++; /* returned value doesn't include room for '\0' */
1093 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1094 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1098 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1099 &dlen
) == ERROR_SUCCESS
) {
1100 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1102 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1103 split_subst_info(&psub
->from
, value
);
1104 split_subst_info(&psub
->to
, data
);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1109 psub
->to
.charset
== DEFAULT_CHARSET
) {
1110 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1111 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1112 HeapFree(GetProcessHeap(), 0, psub
);
1114 add_font_subst(&font_subst_list
, psub
, 0);
1116 /* reset dlen and vlen */
1120 HeapFree(GetProcessHeap(), 0, data
);
1121 HeapFree(GetProcessHeap(), 0, value
);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1138 FT_UInt num_names
, name_index
;
1140 if(FT_IS_SFNT(ft_face
))
1142 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1144 for(name_index
= 0; name_index
< num_names
; name_index
++)
1146 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1148 if((name
.platform_id
== req
->platform_id
) &&
1149 (name
.encoding_id
== req
->encoding_id
) &&
1150 (name
.language_id
== req
->language_id
) &&
1151 (name
.name_id
== req
->name_id
))
1153 req
->string
= name
.string
;
1154 req
->string_len
= name
.string_len
;
1161 req
->string_len
= 0;
1165 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1170 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1171 name
.encoding_id
= TT_MS_ID_UNICODE_CS
;
1172 name
.language_id
= language_id
;
1173 name
.name_id
= name_id
;
1175 if(get_name_table_entry(ft_face
, &name
))
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1181 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1183 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1184 ret
[i
] = GET_BE_WORD(*tmp
);
1187 TRACE("Got localised name %s\n", debugstr_w(ret
));
1193 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1195 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1196 if (f1
->scalable
) return TRUE
;
1197 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1198 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1201 static inline void free_face( Face
*face
)
1203 HeapFree( GetProcessHeap(), 0, face
->file
);
1204 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1205 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1206 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1207 HeapFree( GetProcessHeap(), 0, face
);
1210 static inline void free_family( Family
*family
)
1212 Face
*face
, *cursor2
;
1214 LIST_FOR_EACH_ENTRY_SAFE( face
, cursor2
, &family
->faces
, Face
, entry
)
1216 list_remove( &face
->entry
);
1219 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1220 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1221 HeapFree( GetProcessHeap(), 0, family
);
1224 static inline int style_order(const Face
*face
)
1226 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1234 case NTM_BOLD
| NTM_ITALIC
:
1237 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1238 debugstr_w(face
->family
->FamilyName
),
1239 debugstr_w(face
->StyleName
),
1245 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1249 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1251 if (faces_equal( face
, cursor
))
1253 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1254 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1255 cursor
->font_version
, face
->font_version
);
1257 if (face
->font_version
<= cursor
->font_version
)
1259 TRACE("Original font %s is newer so skipping %s\n",
1260 debugstr_a(cursor
->file
), debugstr_a(face
->file
));
1265 TRACE("Replacing original %s with %s\n",
1266 debugstr_a(cursor
->file
), debugstr_a(face
->file
));
1267 list_add_before( &cursor
->entry
, &face
->entry
);
1268 face
->family
= family
;
1269 list_remove( &cursor
->entry
);
1270 free_face( cursor
);
1275 TRACE("Adding new %s\n", debugstr_a(face
->file
));
1277 if (style_order( face
) < style_order( cursor
)) break;
1280 list_add_before( &cursor
->entry
, &face
->entry
);
1281 face
->family
= family
;
1285 /****************************************************************
1286 * NB This function stores the ptrs to the strings to save copying.
1287 * Don't free them after calling.
1289 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1291 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1292 family
->FamilyName
= name
;
1293 family
->EnglishName
= english_name
;
1294 list_init( &family
->faces
);
1295 family
->replacement
= &family
->faces
;
1300 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1303 LONG r
= RegQueryValueExW(hkey
, value
, NULL
, &type
, NULL
, &needed
);
1304 if(r
!= ERROR_SUCCESS
) return r
;
1305 if(type
!= REG_DWORD
|| needed
!= sizeof(DWORD
)) return ERROR_BAD_CONFIGURATION
;
1306 return RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &needed
);
1309 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1311 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1314 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
)
1317 DWORD num_strikes
, max_strike_key_len
;
1319 /* If we have a File Name key then this is a real font, not just the parent
1320 key of a bunch of non-scalable strikes */
1321 if(RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1324 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1325 face
->cached_enum_data
= NULL
;
1327 face
->file
= HeapAlloc(GetProcessHeap(), 0, needed
);
1328 RegQueryValueExA(hkey_face
, "File Name", NULL
, NULL
, (BYTE
*)face
->file
, &needed
);
1330 face
->StyleName
= strdupW(face_name
);
1332 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
1334 WCHAR
*fullName
= HeapAlloc(GetProcessHeap(), 0, needed
);
1335 RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, (BYTE
*)fullName
, &needed
);
1336 face
->FullName
= fullName
;
1339 face
->FullName
= NULL
;
1341 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1342 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1343 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1344 reg_load_dword(hkey_face
, face_vertical_value
, (DWORD
*)&face
->vertical
);
1346 needed
= sizeof(face
->fs
);
1347 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1349 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1351 face
->scalable
= TRUE
;
1352 memset(&face
->size
, 0, sizeof(face
->size
));
1356 face
->scalable
= FALSE
;
1357 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1358 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1359 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1360 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1361 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1363 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1364 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1365 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1368 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1369 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1370 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1371 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1373 insert_face_in_family_list(face
, family
);
1375 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1378 /* do we have any bitmap strikes? */
1379 RegQueryInfoKeyW(hkey_face
, NULL
, NULL
, NULL
, &num_strikes
, &max_strike_key_len
, NULL
, NULL
,
1380 NULL
, NULL
, NULL
, NULL
);
1381 if(num_strikes
!= 0)
1383 WCHAR strike_name
[10];
1384 DWORD strike_index
= 0;
1386 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1387 while(RegEnumKeyExW(hkey_face
, strike_index
++, strike_name
, &needed
,
1388 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1391 RegOpenKeyExW(hkey_face
, strike_name
, 0, KEY_ALL_ACCESS
, &hkey_strike
);
1392 load_face(hkey_strike
, face_name
, family
);
1393 RegCloseKey(hkey_strike
);
1394 needed
= sizeof(strike_name
) / sizeof(WCHAR
);
1399 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1401 DWORD max_family_key_len
, size
;
1403 DWORD family_index
= 0;
1407 RegQueryInfoKeyW(hkey_font_cache
, NULL
, NULL
, NULL
, NULL
, &max_family_key_len
, NULL
, NULL
,
1408 NULL
, NULL
, NULL
, NULL
);
1409 family_name
= HeapAlloc(GetProcessHeap(), 0, (max_family_key_len
+ 1) * sizeof(WCHAR
));
1411 size
= max_family_key_len
+ 1;
1412 while(RegEnumKeyExW(hkey_font_cache
, family_index
++, family_name
, &size
,
1413 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1415 WCHAR
*english_family
= NULL
;
1416 DWORD face_index
= 0;
1418 DWORD max_face_key_len
;
1420 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1421 TRACE("opened family key %s\n", debugstr_w(family_name
));
1422 if(RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, NULL
, &size
) == ERROR_SUCCESS
)
1424 english_family
= HeapAlloc(GetProcessHeap(), 0, size
);
1425 RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)english_family
, &size
);
1428 family
= create_family(strdupW(family_name
), english_family
);
1429 list_add_tail(&font_list
, &family
->entry
);
1433 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1434 subst
->from
.name
= strdupW(english_family
);
1435 subst
->from
.charset
= -1;
1436 subst
->to
.name
= strdupW(family_name
);
1437 subst
->to
.charset
= -1;
1438 add_font_subst(&font_subst_list
, subst
, 0);
1441 RegQueryInfoKeyW(hkey_family
, NULL
, NULL
, NULL
, NULL
, &max_face_key_len
, NULL
, NULL
,
1442 NULL
, NULL
, NULL
, NULL
);
1444 face_name
= HeapAlloc(GetProcessHeap(), 0, (max_face_key_len
+ 1) * sizeof(WCHAR
));
1445 size
= max_face_key_len
+ 1;
1446 while(RegEnumKeyExW(hkey_family
, face_index
++, face_name
, &size
,
1447 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1451 RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
);
1452 load_face(hkey_face
, face_name
, family
);
1453 RegCloseKey(hkey_face
);
1454 size
= max_face_key_len
+ 1;
1456 HeapFree(GetProcessHeap(), 0, face_name
);
1457 RegCloseKey(hkey_family
);
1458 size
= max_family_key_len
+ 1;
1461 HeapFree(GetProcessHeap(), 0, family_name
);
1464 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1467 HKEY hkey_wine_fonts
;
1469 /* We don't want to create the fonts key as volatile, so open this first */
1470 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1471 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1472 if(ret
!= ERROR_SUCCESS
)
1474 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1478 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1479 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1480 RegCloseKey(hkey_wine_fonts
);
1484 static void add_face_to_cache(Face
*face
)
1486 HKEY hkey_font_cache
, hkey_family
, hkey_face
;
1487 WCHAR
*face_key_name
;
1489 create_font_cache_key(&hkey_font_cache
, NULL
);
1491 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1492 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1493 if(face
->family
->EnglishName
)
1494 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1495 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1498 face_key_name
= face
->StyleName
;
1501 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1502 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1503 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1505 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1508 HeapFree(GetProcessHeap(), 0, face_key_name
);
1510 RegSetValueExA(hkey_face
, "File Name", 0, REG_BINARY
, (BYTE
*)face
->file
, strlen(face
->file
) + 1);
1512 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1513 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1515 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1516 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1517 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1518 reg_save_dword(hkey_face
, face_vertical_value
, face
->vertical
);
1520 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1524 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1525 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1526 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1527 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1528 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1529 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1531 RegCloseKey(hkey_face
);
1532 RegCloseKey(hkey_family
);
1533 RegCloseKey(hkey_font_cache
);
1536 static WCHAR
*prepend_at(WCHAR
*family
)
1543 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1545 strcpyW(str
+ 1, family
);
1546 HeapFree(GetProcessHeap(), 0, family
);
1550 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1552 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1553 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1555 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetUserDefaultLCID() );
1561 else if (!strcmpiW( *name
, *english
))
1563 HeapFree( GetProcessHeap(), 0, *english
);
1569 *name
= prepend_at( *name
);
1570 *english
= prepend_at( *english
);
1574 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1577 WCHAR
*name
, *english_name
;
1579 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1581 family
= find_family_from_name( name
);
1585 family
= create_family( name
, english_name
);
1586 list_add_tail( &font_list
, &family
->entry
);
1590 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1591 subst
->from
.name
= strdupW( english_name
);
1592 subst
->from
.charset
= -1;
1593 subst
->to
.name
= strdupW( name
);
1594 subst
->to
.charset
= -1;
1595 add_font_subst( &font_subst_list
, subst
, 0 );
1600 HeapFree( GetProcessHeap(), 0, name
);
1601 HeapFree( GetProcessHeap(), 0, english_name
);
1607 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1609 FT_Fixed version
= 0;
1612 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1613 if (header
) version
= header
->Font_Revision
;
1618 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1621 FT_ULong table_size
= 0;
1623 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1624 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1625 if (flags
== 0) flags
= NTM_REGULAR
;
1627 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1628 flags
|= NTM_PS_OPENTYPE
;
1633 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1635 int internal_leading
= 0;
1636 FT_WinFNT_HeaderRec winfnt_header
;
1638 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1639 internal_leading
= winfnt_header
.internal_leading
;
1641 return internal_leading
;
1644 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1649 FT_WinFNT_HeaderRec winfnt_header
;
1652 memset( fs
, 0, sizeof(*fs
) );
1654 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1657 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1658 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1659 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1660 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1662 if (os2
->version
== 0)
1664 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1665 fs
->fsCsb
[0] = FS_LATIN1
;
1667 fs
->fsCsb
[0] = FS_SYMBOL
;
1671 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1672 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1677 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1679 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1680 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1681 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1686 if (fs
->fsCsb
[0] == 0)
1688 /* let's see if we can find any interesting cmaps */
1689 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1691 switch (ft_face
->charmaps
[i
]->encoding
)
1693 case FT_ENCODING_UNICODE
:
1694 case FT_ENCODING_APPLE_ROMAN
:
1695 fs
->fsCsb
[0] |= FS_LATIN1
;
1697 case FT_ENCODING_MS_SYMBOL
:
1698 fs
->fsCsb
[0] |= FS_SYMBOL
;
1707 #define ADDFONT_EXTERNAL_FONT 0x01
1708 #define ADDFONT_FORCE_BITMAP 0x02
1709 #define ADDFONT_ADD_TO_CACHE 0x04
1711 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1712 DWORD flags
, BOOL vertical
)
1714 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1715 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1717 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1718 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1721 face
->file
= strdupA( file
);
1722 face
->font_data_ptr
= NULL
;
1723 face
->font_data_size
= 0;
1728 face
->font_data_ptr
= font_data_ptr
;
1729 face
->font_data_size
= font_data_size
;
1732 face
->face_index
= face_index
;
1733 get_fontsig( ft_face
, &face
->fs
);
1734 face
->ntmFlags
= get_ntm_flags( ft_face
);
1735 face
->font_version
= get_font_version( ft_face
);
1737 if (FT_IS_SCALABLE( ft_face
))
1739 memset( &face
->size
, 0, sizeof(face
->size
) );
1740 face
->scalable
= TRUE
;
1744 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1745 size
->height
, size
->width
, size
->size
>> 6,
1746 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1747 face
->size
.height
= size
->height
;
1748 face
->size
.width
= size
->width
;
1749 face
->size
.size
= size
->size
;
1750 face
->size
.x_ppem
= size
->x_ppem
;
1751 face
->size
.y_ppem
= size
->y_ppem
;
1752 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1753 face
->scalable
= FALSE
;
1756 face
->vertical
= vertical
;
1757 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1758 face
->family
= NULL
;
1759 face
->cached_enum_data
= NULL
;
1761 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1762 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1763 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1764 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1769 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1770 FT_Long face_index
, DWORD flags
, BOOL vertical
)
1775 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
, vertical
);
1776 family
= get_family( ft_face
, vertical
);
1777 if (!insert_face_in_family_list( face
, family
))
1783 if (flags
& ADDFONT_ADD_TO_CACHE
)
1784 add_face_to_cache( face
);
1786 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1787 debugstr_w(face
->StyleName
));
1790 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1791 FT_Long face_index
, BOOL allow_bitmap
)
1799 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1800 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1804 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1805 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1810 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1814 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1815 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1817 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1821 if (!FT_IS_SFNT( ft_face
))
1823 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1825 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1831 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1832 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1833 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1835 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1836 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1840 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1841 we don't want to load these. */
1842 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1846 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1848 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1854 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1856 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1862 pFT_Done_Face( ft_face
);
1866 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1869 FT_Long face_index
= 0, num_faces
;
1872 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1873 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1875 #ifdef HAVE_CARBON_CARBON_H
1878 char **mac_list
= expand_mac_font(file
);
1881 BOOL had_one
= FALSE
;
1883 for(cursor
= mac_list
; *cursor
; cursor
++)
1886 AddFontToList(*cursor
, NULL
, 0, flags
);
1887 HeapFree(GetProcessHeap(), 0, *cursor
);
1889 HeapFree(GetProcessHeap(), 0, mac_list
);
1894 #endif /* HAVE_CARBON_CARBON_H */
1897 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_FORCE_BITMAP
);
1898 if (!ft_face
) return 0;
1900 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1902 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1903 pFT_Done_Face(ft_face
);
1907 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, FALSE
);
1910 if (FT_HAS_VERTICAL(ft_face
))
1912 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
, TRUE
);
1916 num_faces
= ft_face
->num_faces
;
1917 pFT_Done_Face(ft_face
);
1918 } while(num_faces
> ++face_index
);
1922 static void DumpFontList(void)
1926 struct list
*family_elem_ptr
, *face_elem_ptr
;
1928 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1929 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1930 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1931 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1932 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1933 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1935 TRACE(" %d", face
->size
.height
);
1942 /***********************************************************
1943 * The replacement list is a way to map an entire font
1944 * family onto another family. For example adding
1946 * [HKCU\Software\Wine\Fonts\Replacements]
1947 * "Wingdings"="Winedings"
1949 * would enumerate the Winedings font both as Winedings and
1950 * Wingdings. However if a real Wingdings font is present the
1951 * replacement does not take place.
1954 static void LoadReplaceList(void)
1957 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1962 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1963 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1965 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1966 &valuelen
, &datalen
, NULL
, NULL
);
1968 valuelen
++; /* returned value doesn't include room for '\0' */
1969 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1970 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1974 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1975 &dlen
) == ERROR_SUCCESS
) {
1976 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1977 /* "NewName"="Oldname" */
1978 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1980 if(!find_family_from_any_name(value
))
1982 Family
* const family
= find_family_from_any_name(data
);
1985 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
1986 if (new_family
!= NULL
)
1988 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
1989 new_family
->FamilyName
= strdupW(value
);
1990 new_family
->EnglishName
= NULL
;
1991 list_init(&new_family
->faces
);
1992 new_family
->replacement
= &family
->faces
;
1993 list_add_tail(&font_list
, &new_family
->entry
);
1998 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2003 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2005 /* reset dlen and vlen */
2009 HeapFree(GetProcessHeap(), 0, data
);
2010 HeapFree(GetProcessHeap(), 0, value
);
2015 static const WCHAR
*font_links_list
[] =
2017 Lucida_Sans_Unicode
,
2018 Microsoft_Sans_Serif
,
2022 static const struct font_links_defaults_list
2024 /* Keyed off substitution for "MS Shell Dlg" */
2025 const WCHAR
*shelldlg
;
2026 /* Maximum of four substitutes, plus terminating NULL pointer */
2027 const WCHAR
*substitutes
[5];
2028 } font_links_defaults_list
[] =
2030 /* Non East-Asian */
2031 { Tahoma
, /* FIXME unverified ordering */
2032 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2034 /* Below lists are courtesy of
2035 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2039 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2041 /* Chinese Simplified */
2043 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2047 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2049 /* Chinese Traditional */
2051 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2056 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2058 SYSTEM_LINKS
*font_link
;
2060 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2062 if(!strcmpiW(font_link
->font_name
, name
))
2069 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2081 SYSTEM_LINKS
*font_link
;
2083 psub
= get_font_subst(&font_subst_list
, name
, -1);
2084 /* Don't store fonts that are only substitutes for other fonts */
2087 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2091 font_link
= find_font_link(name
);
2092 if (font_link
== NULL
)
2094 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2095 font_link
->font_name
= strdupW(name
);
2096 list_init(&font_link
->links
);
2097 list_add_tail(&system_links
, &font_link
->entry
);
2100 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2101 for (i
= 0; values
[i
] != NULL
; i
++)
2103 const struct list
*face_list
;
2104 CHILD_FONT
*child_font
;
2107 if (!strcmpiW(name
,value
))
2109 psub
= get_font_subst(&font_subst_list
, value
, -1);
2111 value
= psub
->to
.name
;
2112 family
= find_family_from_name(value
);
2116 /* Use first extant filename for this Family */
2117 face_list
= get_face_list_from_family(family
);
2118 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2122 file
= strrchr(face
->file
, '/');
2131 fileW
= towstr(CP_UNIXCP
, file
);
2133 face
= find_face_from_filename(fileW
, value
);
2136 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW
), debugstr_w(value
));
2140 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2141 child_font
->face
= face
;
2142 child_font
->font
= NULL
;
2143 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2144 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2145 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2146 list_add_tail(&font_link
->links
, &child_font
->entry
);
2148 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(fileW
));
2149 HeapFree(GetProcessHeap(), 0, fileW
);
2155 /*************************************************************
2158 static BOOL
init_system_links(void)
2162 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2163 WCHAR
*value
, *data
;
2164 WCHAR
*entry
, *next
;
2165 SYSTEM_LINKS
*font_link
, *system_font_link
;
2166 CHILD_FONT
*child_font
;
2167 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2168 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2169 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2174 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2176 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2177 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2178 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2179 val_len
= max_val
+ 1;
2180 data_len
= max_data
;
2182 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2184 psub
= get_font_subst(&font_subst_list
, value
, -1);
2185 /* Don't store fonts that are only substitutes for other fonts */
2188 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2191 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2192 font_link
->font_name
= strdupW(value
);
2193 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2194 list_init(&font_link
->links
);
2195 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2198 CHILD_FONT
*child_font
;
2200 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2202 next
= entry
+ strlenW(entry
) + 1;
2204 face_name
= strchrW(entry
, ',');
2208 while(isspaceW(*face_name
))
2211 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2213 face_name
= psub
->to
.name
;
2215 face
= find_face_from_filename(entry
, face_name
);
2218 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2222 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2223 child_font
->face
= face
;
2224 child_font
->font
= NULL
;
2225 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2226 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2227 TRACE("Adding file %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2228 list_add_tail(&font_link
->links
, &child_font
->entry
);
2230 list_add_tail(&system_links
, &font_link
->entry
);
2232 val_len
= max_val
+ 1;
2233 data_len
= max_data
;
2236 HeapFree(GetProcessHeap(), 0, value
);
2237 HeapFree(GetProcessHeap(), 0, data
);
2242 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2244 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2248 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2250 const FontSubst
*psub2
;
2251 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2253 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2255 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2256 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2258 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2259 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2261 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2263 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2269 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2272 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2273 system_font_link
->font_name
= strdupW(System
);
2274 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2275 list_init(&system_font_link
->links
);
2277 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2280 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2281 child_font
->face
= face
;
2282 child_font
->font
= NULL
;
2283 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2284 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2285 TRACE("Found Tahoma in %s index %ld\n", child_font
->face
->file
, child_font
->face
->face_index
);
2286 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2288 font_link
= find_font_link(Tahoma
);
2289 if (font_link
!= NULL
)
2291 CHILD_FONT
*font_link_entry
;
2292 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2294 CHILD_FONT
*new_child
;
2295 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2296 new_child
->face
= font_link_entry
->face
;
2297 new_child
->font
= NULL
;
2298 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2299 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2300 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2303 list_add_tail(&system_links
, &system_font_link
->entry
);
2307 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2310 struct dirent
*dent
;
2311 char path
[MAX_PATH
];
2313 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2315 dir
= opendir(dirname
);
2317 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2320 while((dent
= readdir(dir
)) != NULL
) {
2321 struct stat statbuf
;
2323 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2326 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2328 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2330 if(stat(path
, &statbuf
) == -1)
2332 WARN("Can't stat %s\n", debugstr_a(path
));
2335 if(S_ISDIR(statbuf
.st_mode
))
2336 ReadFontDir(path
, external_fonts
);
2339 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2340 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2341 AddFontToList(path
, NULL
, 0, addfont_flags
);
2348 #ifdef SONAME_LIBFONTCONFIG
2349 static void load_fontconfig_fonts(void)
2351 void *fc_handle
= NULL
;
2360 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2362 TRACE("Wine cannot find the fontconfig library (%s).\n",
2363 SONAME_LIBFONTCONFIG
);
2366 #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;}
2367 LOAD_FUNCPTR(FcConfigGetCurrent
);
2368 LOAD_FUNCPTR(FcFontList
);
2369 LOAD_FUNCPTR(FcFontSetDestroy
);
2370 LOAD_FUNCPTR(FcInit
);
2371 LOAD_FUNCPTR(FcObjectSetAdd
);
2372 LOAD_FUNCPTR(FcObjectSetCreate
);
2373 LOAD_FUNCPTR(FcObjectSetDestroy
);
2374 LOAD_FUNCPTR(FcPatternCreate
);
2375 LOAD_FUNCPTR(FcPatternDestroy
);
2376 LOAD_FUNCPTR(FcPatternGetBool
);
2377 LOAD_FUNCPTR(FcPatternGetString
);
2380 if(!pFcInit()) return;
2382 config
= pFcConfigGetCurrent();
2383 pat
= pFcPatternCreate();
2384 os
= pFcObjectSetCreate();
2385 pFcObjectSetAdd(os
, FC_FILE
);
2386 pFcObjectSetAdd(os
, FC_SCALABLE
);
2387 fontset
= pFcFontList(config
, pat
, os
);
2388 if(!fontset
) return;
2389 for(i
= 0; i
< fontset
->nfont
; i
++) {
2392 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2394 TRACE("fontconfig: %s\n", file
);
2396 /* We're just interested in OT/TT fonts for now, so this hack just
2397 picks up the scalable fonts without extensions .pf[ab] to save time
2398 loading every other font */
2400 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2402 TRACE("not scalable\n");
2406 len
= strlen( file
);
2407 if(len
< 4) continue;
2408 ext
= &file
[ len
- 3 ];
2409 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2410 AddFontToList(file
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2412 pFcFontSetDestroy(fontset
);
2413 pFcObjectSetDestroy(os
);
2414 pFcPatternDestroy(pat
);
2419 #elif defined(HAVE_CARBON_CARBON_H)
2421 static void load_mac_font_callback(const void *value
, void *context
)
2423 CFStringRef pathStr
= value
;
2427 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2428 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2429 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2431 TRACE("font file %s\n", path
);
2432 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2434 HeapFree(GetProcessHeap(), 0, path
);
2437 static void load_mac_fonts(void)
2439 CFStringRef removeDupesKey
;
2440 CFBooleanRef removeDupesValue
;
2441 CFDictionaryRef options
;
2442 CTFontCollectionRef col
;
2444 CFMutableSetRef paths
;
2447 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2448 removeDupesValue
= kCFBooleanTrue
;
2449 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2450 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2451 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2452 if (options
) CFRelease(options
);
2455 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2459 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2463 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2467 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2470 WARN("CFSetCreateMutable failed\n");
2475 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2477 CTFontDescriptorRef desc
;
2486 desc
= CFArrayGetValueAtIndex(descs
, i
);
2488 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2489 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2490 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2491 if (!font
) continue;
2493 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2500 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2502 if (status
!= noErr
) continue;
2504 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2507 ext
= CFURLCopyPathExtension(url
);
2510 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2511 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2520 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2522 if (!path
) continue;
2524 CFSetAddValue(paths
, path
);
2530 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2536 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2539 const char *data_dir
= wine_get_data_dir();
2541 if (!data_dir
) data_dir
= wine_get_build_dir();
2548 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2550 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2552 strcpy(unix_name
, data_dir
);
2553 strcat(unix_name
, "/fonts/");
2555 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2557 EnterCriticalSection( &freetype_cs
);
2558 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2559 LeaveCriticalSection( &freetype_cs
);
2560 HeapFree(GetProcessHeap(), 0, unix_name
);
2565 static BOOL
load_font_from_winfonts_dir(LPCWSTR file
)
2567 static const WCHAR slashW
[] = {'\\','\0'};
2569 WCHAR windowsdir
[MAX_PATH
];
2572 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2573 strcatW(windowsdir
, fontsW
);
2574 strcatW(windowsdir
, slashW
);
2575 strcatW(windowsdir
, file
);
2576 if ((unixname
= wine_get_unix_file_name(windowsdir
))) {
2577 EnterCriticalSection( &freetype_cs
);
2578 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
);
2579 LeaveCriticalSection( &freetype_cs
);
2580 HeapFree(GetProcessHeap(), 0, unixname
);
2585 static void load_system_fonts(void)
2588 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2589 const WCHAR
* const *value
;
2591 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2594 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2595 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2596 strcatW(windowsdir
, fontsW
);
2597 for(value
= SystemFontValues
; *value
; value
++) {
2598 dlen
= sizeof(data
);
2599 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2603 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2604 if((unixname
= wine_get_unix_file_name(pathW
))) {
2605 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2606 HeapFree(GetProcessHeap(), 0, unixname
);
2609 load_font_from_data_dir(data
);
2616 /*************************************************************
2618 * This adds registry entries for any externally loaded fonts
2619 * (fonts from fontconfig or FontDirs). It also deletes entries
2620 * of no longer existing fonts.
2623 static void update_reg_entries(void)
2625 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2630 struct list
*family_elem_ptr
, *face_elem_ptr
;
2632 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2633 static const WCHAR spaceW
[] = {' ', '\0'};
2636 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2637 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2638 ERR("Can't create Windows font reg key\n");
2642 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2643 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2644 ERR("Can't create Windows font reg key\n");
2648 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2649 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2650 ERR("Can't create external font reg key\n");
2654 /* enumerate the fonts and add external ones to the two keys */
2656 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2657 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2658 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2659 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2660 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2661 if(!face
->external
) continue;
2663 if (!(face
->ntmFlags
& NTM_REGULAR
))
2664 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
2665 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2666 strcpyW(valueW
, family
->FamilyName
);
2667 if(len
!= len_fam
) {
2668 strcatW(valueW
, spaceW
);
2669 strcatW(valueW
, face
->StyleName
);
2671 strcatW(valueW
, TrueType
);
2673 file
= wine_get_dos_file_name(face
->file
);
2675 len
= strlenW(file
) + 1;
2678 if((path
= strrchr(face
->file
, '/')) == NULL
)
2682 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
2684 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2685 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
2687 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2688 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2689 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2691 HeapFree(GetProcessHeap(), 0, file
);
2692 HeapFree(GetProcessHeap(), 0, valueW
);
2696 if(external_key
) RegCloseKey(external_key
);
2697 if(win9x_key
) RegCloseKey(win9x_key
);
2698 if(winnt_key
) RegCloseKey(winnt_key
);
2702 static void delete_external_font_keys(void)
2704 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2705 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2709 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2710 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2711 ERR("Can't create Windows font reg key\n");
2715 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2716 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2717 ERR("Can't create Windows font reg key\n");
2721 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2722 ERR("Can't create external font reg key\n");
2726 /* Delete all external fonts added last time */
2728 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2729 &valuelen
, &datalen
, NULL
, NULL
);
2730 valuelen
++; /* returned value doesn't include room for '\0' */
2731 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2732 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2734 dlen
= datalen
* sizeof(WCHAR
);
2737 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2738 &dlen
) == ERROR_SUCCESS
) {
2740 RegDeleteValueW(winnt_key
, valueW
);
2741 RegDeleteValueW(win9x_key
, valueW
);
2742 /* reset dlen and vlen */
2746 HeapFree(GetProcessHeap(), 0, data
);
2747 HeapFree(GetProcessHeap(), 0, valueW
);
2749 /* Delete the old external fonts key */
2750 RegCloseKey(external_key
);
2751 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2754 if(win9x_key
) RegCloseKey(win9x_key
);
2755 if(winnt_key
) RegCloseKey(winnt_key
);
2758 /*************************************************************
2759 * WineEngAddFontResourceEx
2762 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2768 if (ft_handle
) /* do it only if we have freetype up and running */
2773 FIXME("Ignoring flags %x\n", flags
);
2775 if((unixname
= wine_get_unix_file_name(file
)))
2777 DWORD addfont_flags
= ADDFONT_FORCE_BITMAP
;
2779 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2780 EnterCriticalSection( &freetype_cs
);
2781 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2782 LeaveCriticalSection( &freetype_cs
);
2783 HeapFree(GetProcessHeap(), 0, unixname
);
2785 if (!ret
&& !strchrW(file
, '\\')) {
2786 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2787 ret
= load_font_from_winfonts_dir(file
);
2789 /* Try in datadir/fonts (or builddir/fonts),
2790 * needed for Magic the Gathering Online
2792 ret
= load_font_from_data_dir(file
);
2799 /*************************************************************
2800 * WineEngAddFontMemResourceEx
2803 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2807 if (ft_handle
) /* do it only if we have freetype up and running */
2809 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2811 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2812 memcpy(pFontCopy
, pbFont
, cbFont
);
2814 EnterCriticalSection( &freetype_cs
);
2815 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_FORCE_BITMAP
);
2816 LeaveCriticalSection( &freetype_cs
);
2820 TRACE("AddFontToList failed\n");
2821 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2824 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2825 * For now return something unique but quite random
2827 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2828 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2835 /*************************************************************
2836 * WineEngRemoveFontResourceEx
2839 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2842 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
2846 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
2852 if (!font_file
) return NULL
;
2854 file_len
= strlenW( font_file
);
2856 if (font_path
&& font_path
[0])
2858 int path_len
= strlenW( font_path
);
2859 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
2860 if (!fullname
) return NULL
;
2861 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
2862 fullname
[path_len
] = '\\';
2863 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
2867 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
2868 if (!len
) return NULL
;
2869 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2870 if (!fullname
) return NULL
;
2871 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
2874 unix_name
= wine_get_unix_file_name( fullname
);
2875 HeapFree( GetProcessHeap(), 0, fullname
);
2879 #include <pshpack1.h>
2882 WORD num_of_resources
;
2886 CHAR dfCopyright
[60];
2892 WORD dfInternalLeading
;
2893 WORD dfExternalLeading
;
2901 BYTE dfPitchAndFamily
;
2912 CHAR szFaceName
[LF_FACESIZE
];
2915 #include <poppack.h>
2917 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
2918 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
2920 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
2922 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
2925 WCHAR
*name
, *english_name
;
2927 NEWTEXTMETRICEXW ntm
;
2930 if (!ft_face
) return FALSE
;
2931 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0, FALSE
);
2932 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
2933 family
= create_family( name
, english_name
);
2934 insert_face_in_family_list( face
, family
);
2935 pFT_Done_Face( ft_face
);
2937 GetEnumStructs( face
, &elf
, &ntm
, &type
);
2938 free_family( family
);
2940 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
2942 memset( fd
, 0, sizeof(*fd
) );
2944 fd
->num_of_resources
= 1;
2946 fd
->dfVersion
= 0x200;
2947 fd
->dfSize
= sizeof(*fd
);
2948 strcpy( fd
->dfCopyright
, "Wine fontdir" );
2949 fd
->dfType
= 0x4003; /* 0x0080 set if private */
2950 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
2952 fd
->dfHorizRes
= 72;
2953 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
2954 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
2955 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
2956 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
2957 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
2958 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
2959 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
2960 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
2962 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
2963 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
2964 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
2965 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
2966 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
2967 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
2968 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
2969 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
2970 fd
->dfWidthBytes
= 0;
2972 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
2974 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
2979 #define NE_FFLAGS_LIBMODULE 0x8000
2980 #define NE_OSFLAGS_WINDOWS 0x02
2982 static const char dos_string
[0x40] = "This is a TrueType resource file";
2983 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
2985 #include <pshpack2.h>
3006 struct ne_typeinfo fontdir_type
;
3007 struct ne_nameinfo fontdir_name
;
3008 struct ne_typeinfo scalable_type
;
3009 struct ne_nameinfo scalable_name
;
3011 BYTE fontdir_res_name
[8];
3014 #include <poppack.h>
3016 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3020 DWORD size
, written
;
3022 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3023 char *font_fileA
, *last_part
, *ext
;
3024 IMAGE_DOS_HEADER dos
;
3025 IMAGE_OS2_HEADER ne
=
3027 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3029 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3030 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3032 struct rsrc_tab rsrc_tab
=
3036 { 0, 0, 0x0c50, 0x2c, 0 },
3038 { 0, 0, 0x0c50, 0x8001, 0 },
3040 { 7,'F','O','N','T','D','I','R'}
3043 memset( &dos
, 0, sizeof(dos
) );
3044 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3045 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3047 /* import name is last part\0, resident name is last part without extension
3048 non-resident name is "FONTRES:" + lfFaceName */
3050 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3051 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3052 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3054 last_part
= strrchr( font_fileA
, '\\' );
3055 if (last_part
) last_part
++;
3056 else last_part
= font_fileA
;
3057 import_name_len
= strlen( last_part
) + 1;
3059 ext
= strchr( last_part
, '.' );
3060 if (ext
) res_name_len
= ext
- last_part
;
3061 else res_name_len
= import_name_len
- 1;
3063 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3065 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3066 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3067 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3068 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3070 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3072 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3073 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3074 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3075 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3077 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3078 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3082 HeapFree( GetProcessHeap(), 0, font_fileA
);
3086 memcpy( ptr
, &dos
, sizeof(dos
) );
3087 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3088 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3090 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3091 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3093 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3094 *ptr
++ = res_name_len
;
3095 memcpy( ptr
, last_part
, res_name_len
);
3097 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3098 *ptr
++ = import_name_len
;
3099 memcpy( ptr
, last_part
, import_name_len
);
3101 ptr
= start
+ ne
.ne_nrestab
;
3102 *ptr
++ = non_res_name_len
;
3103 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3104 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3106 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3107 memcpy( ptr
, font_fileA
, font_file_len
);
3109 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3110 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3112 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3113 if (file
!= INVALID_HANDLE_VALUE
)
3115 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3117 CloseHandle( file
);
3120 HeapFree( GetProcessHeap(), 0, start
);
3121 HeapFree( GetProcessHeap(), 0, font_fileA
);
3126 /*************************************************************
3127 * WineEngCreateScalableFontResource
3130 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3131 LPCWSTR font_file
, LPCWSTR font_path
)
3133 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3134 struct fontdir fontdir
;
3137 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3138 SetLastError( ERROR_INVALID_PARAMETER
);
3141 if (hidden
) fontdir
.dfType
|= 0x80;
3142 ret
= create_fot( resource
, font_file
, &fontdir
);
3145 HeapFree( GetProcessHeap(), 0, unix_name
);
3149 static const struct nls_update_font_list
3151 UINT ansi_cp
, oem_cp
;
3152 const char *oem
, *fixed
, *system
;
3153 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3154 /* these are for font substitutes */
3155 const char *shelldlg
, *tmsrmn
;
3156 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3160 const char *from
, *to
;
3161 } arial_0
, courier_new_0
, times_new_roman_0
;
3162 } nls_update_font_list
[] =
3164 /* Latin 1 (United States) */
3165 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3166 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3167 "Tahoma","Times New Roman",
3168 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3171 /* Latin 1 (Multilingual) */
3172 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3173 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3174 "Tahoma","Times New Roman", /* FIXME unverified */
3175 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3178 /* Eastern Europe */
3179 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3180 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3181 "Tahoma","Times New Roman", /* FIXME unverified */
3182 "Fixedsys,238", "System,238",
3183 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3184 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3185 { "Arial CE,0", "Arial,238" },
3186 { "Courier New CE,0", "Courier New,238" },
3187 { "Times New Roman CE,0", "Times New Roman,238" }
3190 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3191 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3192 "Tahoma","Times New Roman", /* FIXME unverified */
3193 "Fixedsys,204", "System,204",
3194 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3195 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3196 { "Arial Cyr,0", "Arial,204" },
3197 { "Courier New Cyr,0", "Courier New,204" },
3198 { "Times New Roman Cyr,0", "Times New Roman,204" }
3201 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3202 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3203 "Tahoma","Times New Roman", /* FIXME unverified */
3204 "Fixedsys,161", "System,161",
3205 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3206 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3207 { "Arial Greek,0", "Arial,161" },
3208 { "Courier New Greek,0", "Courier New,161" },
3209 { "Times New Roman Greek,0", "Times New Roman,161" }
3212 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3213 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3214 "Tahoma","Times New Roman", /* FIXME unverified */
3215 "Fixedsys,162", "System,162",
3216 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3217 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3218 { "Arial Tur,0", "Arial,162" },
3219 { "Courier New Tur,0", "Courier New,162" },
3220 { "Times New Roman Tur,0", "Times New Roman,162" }
3223 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3224 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3225 "Tahoma","Times New Roman", /* FIXME unverified */
3226 "Fixedsys,177", "System,177",
3227 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3228 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3232 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3233 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3234 "Tahoma","Times New Roman", /* FIXME unverified */
3235 "Fixedsys,178", "System,178",
3236 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3237 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3241 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3242 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3243 "Tahoma","Times New Roman", /* FIXME unverified */
3244 "Fixedsys,186", "System,186",
3245 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3246 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3247 { "Arial Baltic,0", "Arial,186" },
3248 { "Courier New Baltic,0", "Courier New,186" },
3249 { "Times New Roman Baltic,0", "Times New Roman,186" }
3252 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3253 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3254 "Tahoma","Times New Roman", /* FIXME unverified */
3255 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3259 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3260 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3261 "Tahoma","Times New Roman", /* FIXME unverified */
3262 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3266 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3267 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3268 "MS UI Gothic","MS Serif",
3269 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3272 /* Chinese Simplified */
3273 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3274 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3275 "SimSun", "NSimSun",
3276 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3280 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3281 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3283 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3286 /* Chinese Traditional */
3287 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3288 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3289 "PMingLiU", "MingLiU",
3290 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3295 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3297 return ( ansi_cp
== 932 /* CP932 for Japanese */
3298 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3299 || ansi_cp
== 949 /* CP949 for Korean */
3300 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3303 static inline HKEY
create_fonts_NT_registry_key(void)
3307 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3308 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3312 static inline HKEY
create_fonts_9x_registry_key(void)
3316 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3317 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3321 static inline HKEY
create_config_fonts_registry_key(void)
3325 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3326 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3330 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3332 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3334 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3335 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3336 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3337 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3340 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3343 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3345 RegDeleteValueA(hkey
, name
);
3348 static void update_font_info(void)
3350 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3351 char buf
[40], cpbuf
[40];
3354 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3355 DWORD screen_dpi
= 96, font_dpi
= 0;
3358 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3359 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3360 &hkey
) == ERROR_SUCCESS
)
3362 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3366 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3369 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3371 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3372 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3373 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3374 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3375 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3377 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3378 if (is_dbcs_ansi_cp(ansi_cp
))
3379 use_default_fallback
= TRUE
;
3382 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3384 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3389 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3390 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3392 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3393 ansi_cp
, oem_cp
, screen_dpi
);
3395 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3396 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3399 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3403 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3404 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3406 hkey
= create_config_fonts_registry_key();
3407 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3408 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3409 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3412 hkey
= create_fonts_NT_registry_key();
3413 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3416 hkey
= create_fonts_9x_registry_key();
3417 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3420 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3422 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3423 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3424 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3425 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3427 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3428 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3429 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3430 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3431 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3432 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3433 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3434 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3436 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3437 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3438 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3446 /* Delete the FontSubstitutes from other locales */
3447 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3449 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3450 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3451 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3457 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3460 static BOOL
init_freetype(void)
3462 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3465 "Wine cannot find the FreeType font library. To enable Wine to\n"
3466 "use TrueType fonts please install a version of FreeType greater than\n"
3467 "or equal to 2.0.5.\n"
3468 "http://www.freetype.org\n");
3472 #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;}
3474 LOAD_FUNCPTR(FT_Done_Face
)
3475 LOAD_FUNCPTR(FT_Get_Char_Index
)
3476 LOAD_FUNCPTR(FT_Get_First_Char
)
3477 LOAD_FUNCPTR(FT_Get_Module
)
3478 LOAD_FUNCPTR(FT_Get_Next_Char
)
3479 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3480 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3481 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3482 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3483 LOAD_FUNCPTR(FT_Init_FreeType
)
3484 LOAD_FUNCPTR(FT_Library_Version
)
3485 LOAD_FUNCPTR(FT_Load_Glyph
)
3486 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3487 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3488 #ifndef FT_MULFIX_INLINED
3489 LOAD_FUNCPTR(FT_MulFix
)
3491 LOAD_FUNCPTR(FT_New_Face
)
3492 LOAD_FUNCPTR(FT_New_Memory_Face
)
3493 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3494 LOAD_FUNCPTR(FT_Outline_Transform
)
3495 LOAD_FUNCPTR(FT_Outline_Translate
)
3496 LOAD_FUNCPTR(FT_Render_Glyph
)
3497 LOAD_FUNCPTR(FT_Select_Charmap
)
3498 LOAD_FUNCPTR(FT_Set_Charmap
)
3499 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3500 LOAD_FUNCPTR(FT_Vector_Transform
)
3501 LOAD_FUNCPTR(FT_Vector_Unit
)
3503 /* Don't warn if these ones are missing */
3504 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3505 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3506 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3509 if(pFT_Init_FreeType(&library
) != 0) {
3510 ERR("Can't init FreeType library\n");
3511 wine_dlclose(ft_handle
, NULL
, 0);
3515 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3517 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3518 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3519 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3520 ((FT_Version
.patch
) & 0x0000ff);
3522 font_driver
= &freetype_funcs
;
3527 "Wine cannot find certain functions that it needs inside the FreeType\n"
3528 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3529 "FreeType to at least version 2.1.4.\n"
3530 "http://www.freetype.org\n");
3531 wine_dlclose(ft_handle
, NULL
, 0);
3536 static void init_font_list(void)
3538 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3539 static const WCHAR pathW
[] = {'P','a','t','h',0};
3541 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3542 WCHAR windowsdir
[MAX_PATH
];
3544 const char *data_dir
;
3546 delete_external_font_keys();
3548 /* load the system bitmap fonts */
3549 load_system_fonts();
3551 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3552 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3553 strcatW(windowsdir
, fontsW
);
3554 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3556 ReadFontDir(unixname
, FALSE
);
3557 HeapFree(GetProcessHeap(), 0, unixname
);
3560 /* load the system truetype fonts */
3561 data_dir
= wine_get_data_dir();
3562 if (!data_dir
) data_dir
= wine_get_build_dir();
3563 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3565 strcpy(unixname
, data_dir
);
3566 strcat(unixname
, "/fonts/");
3567 ReadFontDir(unixname
, TRUE
);
3568 HeapFree(GetProcessHeap(), 0, unixname
);
3571 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3572 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3573 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3575 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3576 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3577 &hkey
) == ERROR_SUCCESS
)
3579 LPWSTR data
, valueW
;
3580 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3581 &valuelen
, &datalen
, NULL
, NULL
);
3583 valuelen
++; /* returned value doesn't include room for '\0' */
3584 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3585 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3588 dlen
= datalen
* sizeof(WCHAR
);
3590 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3591 &dlen
) == ERROR_SUCCESS
)
3593 if(data
[0] && (data
[1] == ':'))
3595 if((unixname
= wine_get_unix_file_name(data
)))
3597 AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3598 HeapFree(GetProcessHeap(), 0, unixname
);
3601 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3603 WCHAR pathW
[MAX_PATH
];
3604 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3607 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3608 if((unixname
= wine_get_unix_file_name(pathW
)))
3610 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_FORCE_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3611 HeapFree(GetProcessHeap(), 0, unixname
);
3614 load_font_from_data_dir(data
);
3616 /* reset dlen and vlen */
3621 HeapFree(GetProcessHeap(), 0, data
);
3622 HeapFree(GetProcessHeap(), 0, valueW
);
3626 #ifdef SONAME_LIBFONTCONFIG
3627 load_fontconfig_fonts();
3628 #elif defined(HAVE_CARBON_CARBON_H)
3632 /* then look in any directories that we've specified in the config file */
3633 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3634 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3640 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3642 len
+= sizeof(WCHAR
);
3643 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3644 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3646 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3647 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3648 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3649 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3654 LPSTR next
= strchr( ptr
, ':' );
3655 if (next
) *next
++ = 0;
3656 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3657 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3659 strcpy( unixname
, home
);
3660 strcat( unixname
, ptr
+ 1 );
3661 ReadFontDir( unixname
, TRUE
);
3662 HeapFree( GetProcessHeap(), 0, unixname
);
3665 ReadFontDir( ptr
, TRUE
);
3668 HeapFree( GetProcessHeap(), 0, valueA
);
3670 HeapFree( GetProcessHeap(), 0, valueW
);
3676 static BOOL
move_to_front(const WCHAR
*name
)
3678 Family
*family
, *cursor2
;
3679 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3681 if(!strcmpiW(family
->FamilyName
, name
))
3683 list_remove(&family
->entry
);
3684 list_add_head(&font_list
, &family
->entry
);
3691 static BOOL
set_default(const WCHAR
**name_list
)
3695 if (move_to_front(*name_list
)) return TRUE
;
3702 static void reorder_font_list(void)
3704 set_default( default_serif_list
);
3705 set_default( default_fixed_list
);
3706 set_default( default_sans_list
);
3709 /*************************************************************
3712 * Initialize FreeType library and create a list of available faces
3714 BOOL
WineEngInit(void)
3716 HKEY hkey_font_cache
;
3720 /* update locale dependent font info in registry */
3723 if(!init_freetype()) return FALSE
;
3725 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3727 ERR("Failed to create font mutex\n");
3730 WaitForSingleObject(font_mutex
, INFINITE
);
3732 create_font_cache_key(&hkey_font_cache
, &disposition
);
3734 if(disposition
== REG_CREATED_NEW_KEY
)
3737 load_font_list_from_cache(hkey_font_cache
);
3739 RegCloseKey(hkey_font_cache
);
3741 reorder_font_list();
3748 if(disposition
== REG_CREATED_NEW_KEY
)
3749 update_reg_entries();
3751 init_system_links();
3753 ReleaseMutex(font_mutex
);
3758 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3761 TT_HoriHeader
*pHori
;
3765 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3766 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3768 if(height
== 0) height
= 16;
3770 /* Calc. height of EM square:
3772 * For +ve lfHeight we have
3773 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3774 * Re-arranging gives:
3775 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3777 * For -ve lfHeight we have
3779 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3780 * with il = winAscent + winDescent - units_per_em]
3785 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
3786 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3787 pHori
->Ascender
- pHori
->Descender
);
3789 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
3790 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
3798 static struct font_mapping
*map_font_file( const char *name
)
3800 struct font_mapping
*mapping
;
3804 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
3805 if (fstat( fd
, &st
) == -1) goto error
;
3807 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
3809 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
3811 mapping
->refcount
++;
3816 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
3819 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
3822 if (mapping
->data
== MAP_FAILED
)
3824 HeapFree( GetProcessHeap(), 0, mapping
);
3827 mapping
->refcount
= 1;
3828 mapping
->dev
= st
.st_dev
;
3829 mapping
->ino
= st
.st_ino
;
3830 mapping
->size
= st
.st_size
;
3831 list_add_tail( &mappings_list
, &mapping
->entry
);
3839 static void unmap_font_file( struct font_mapping
*mapping
)
3841 if (!--mapping
->refcount
)
3843 list_remove( &mapping
->entry
);
3844 munmap( mapping
->data
, mapping
->size
);
3845 HeapFree( GetProcessHeap(), 0, mapping
);
3849 static LONG
load_VDMX(GdiFont
*, LONG
);
3851 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
3858 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
3862 if (!(font
->mapping
= map_font_file( face
->file
)))
3864 WARN("failed to map %s\n", debugstr_a(face
->file
));
3867 data_ptr
= font
->mapping
->data
;
3868 data_size
= font
->mapping
->size
;
3872 data_ptr
= face
->font_data_ptr
;
3873 data_size
= face
->font_data_size
;
3876 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
3878 ERR("FT_New_Face rets %d\n", err
);
3882 /* set it here, as load_VDMX needs it */
3883 font
->ft_face
= ft_face
;
3885 if(FT_IS_SCALABLE(ft_face
)) {
3886 /* load the VDMX table if we have one */
3887 font
->ppem
= load_VDMX(font
, height
);
3889 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
3890 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
3892 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
3893 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
3895 font
->ppem
= height
;
3896 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
3897 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
3903 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
3905 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3906 a single face with the requested charset. The idea is to check if
3907 the selected font supports the current ANSI codepage, if it does
3908 return the corresponding charset, else return the first charset */
3911 int acp
= GetACP(), i
;
3915 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
3917 const SYSTEM_LINKS
*font_link
;
3919 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
3920 return csi
.ciCharset
;
3922 font_link
= find_font_link(family_name
);
3923 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
3924 return csi
.ciCharset
;
3927 for(i
= 0; i
< 32; i
++) {
3929 if(face
->fs
.fsCsb
[0] & fs0
) {
3930 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
3932 return csi
.ciCharset
;
3935 FIXME("TCI failing on %x\n", fs0
);
3939 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3940 face
->fs
.fsCsb
[0], face
->file
);
3942 return DEFAULT_CHARSET
;
3945 static GdiFont
*alloc_font(void)
3947 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
3949 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
3950 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3952 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
3953 ret
->total_kern_pairs
= (DWORD
)-1;
3954 ret
->kern_pairs
= NULL
;
3955 list_init(&ret
->hfontlist
);
3956 list_init(&ret
->child_fonts
);
3960 static void free_font(GdiFont
*font
)
3962 struct list
*cursor
, *cursor2
;
3965 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
3967 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
3968 list_remove(cursor
);
3970 free_font(child
->font
);
3971 HeapFree(GetProcessHeap(), 0, child
);
3974 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->hfontlist
)
3976 HFONTLIST
*hfontlist
= LIST_ENTRY(cursor
, HFONTLIST
, entry
);
3977 DeleteObject(hfontlist
->hfont
);
3978 list_remove(&hfontlist
->entry
);
3979 HeapFree(GetProcessHeap(), 0, hfontlist
);
3982 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
3983 if (font
->mapping
) unmap_font_file( font
->mapping
);
3984 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
3985 HeapFree(GetProcessHeap(), 0, font
->potm
);
3986 HeapFree(GetProcessHeap(), 0, font
->name
);
3987 for (i
= 0; i
< font
->gmsize
; i
++)
3988 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
3989 HeapFree(GetProcessHeap(), 0, font
->gm
);
3990 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
3991 HeapFree(GetProcessHeap(), 0, font
);
3995 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
3997 FT_Face ft_face
= font
->ft_face
;
4001 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4008 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4010 /* make sure value of len is the value freetype says it needs */
4013 FT_ULong needed
= 0;
4014 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4015 if( !err
&& needed
< len
) len
= needed
;
4017 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4020 TRACE("Can't find table %c%c%c%c\n",
4021 /* bytes were reversed */
4022 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4023 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4029 /*************************************************************
4032 * load the vdmx entry for the specified height
4035 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4036 ( ( (FT_ULong)_x4 << 24 ) | \
4037 ( (FT_ULong)_x3 << 16 ) | \
4038 ( (FT_ULong)_x2 << 8 ) | \
4041 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4056 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4060 BYTE devXRatio
, devYRatio
;
4061 USHORT numRecs
, numRatios
;
4062 DWORD result
, offset
= -1;
4066 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4068 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4071 /* FIXME: need the real device aspect ratio */
4075 numRecs
= GET_BE_WORD(hdr
[1]);
4076 numRatios
= GET_BE_WORD(hdr
[2]);
4078 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4079 for(i
= 0; i
< numRatios
; i
++) {
4082 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4083 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4086 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4088 if((ratio
.xRatio
== 0 &&
4089 ratio
.yStartRatio
== 0 &&
4090 ratio
.yEndRatio
== 0) ||
4091 (devXRatio
== ratio
.xRatio
&&
4092 devYRatio
>= ratio
.yStartRatio
&&
4093 devYRatio
<= ratio
.yEndRatio
))
4095 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4096 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4097 offset
= GET_BE_WORD(tmp
);
4103 FIXME("No suitable ratio found\n");
4107 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4109 BYTE startsz
, endsz
;
4112 recs
= GET_BE_WORD(group
.recs
);
4113 startsz
= group
.startsz
;
4114 endsz
= group
.endsz
;
4116 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4118 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4119 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4120 if(result
== GDI_ERROR
) {
4121 FIXME("Failed to retrieve vTable\n");
4126 for(i
= 0; i
< recs
; i
++) {
4127 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4128 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4129 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4131 if(yMax
+ -yMin
== height
) {
4134 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4137 if(yMax
+ -yMin
> height
) {
4140 goto end
; /* failed */
4142 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4143 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4144 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4145 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4151 TRACE("ppem not found for height %d\n", height
);
4155 HeapFree(GetProcessHeap(), 0, vTable
);
4161 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4163 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4164 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4165 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4166 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4167 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4170 static void calc_hash(FONT_DESC
*pfd
)
4172 DWORD hash
= 0, *ptr
, two_chars
;
4176 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4178 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4180 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4182 pwc
= (WCHAR
*)&two_chars
;
4184 *pwc
= toupperW(*pwc
);
4186 *pwc
= toupperW(*pwc
);
4190 hash
^= !pfd
->can_use_bitmap
;
4195 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4200 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4204 fd
.can_use_bitmap
= can_use_bitmap
;
4207 /* try the child list */
4208 LIST_FOR_EACH(font_elem_ptr
, &child_font_list
) {
4209 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4210 if(!fontcmp(ret
, &fd
)) {
4211 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4212 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
4213 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4214 if(hflist
->hfont
== hfont
)
4220 /* try the in-use list */
4221 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
4222 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4223 if(!fontcmp(ret
, &fd
)) {
4224 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4225 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
4226 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4227 if(hflist
->hfont
== hfont
)
4230 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4231 hflist
->hfont
= hfont
;
4232 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4237 /* then the unused list */
4238 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4239 while(font_elem_ptr
) {
4240 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4241 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4242 if(!fontcmp(ret
, &fd
)) {
4243 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4244 assert(list_empty(&ret
->hfontlist
));
4245 TRACE("Found %p in unused list\n", ret
);
4246 list_remove(&ret
->entry
);
4247 list_add_head(&gdi_font_list
, &ret
->entry
);
4248 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4249 hflist
->hfont
= hfont
;
4250 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4257 static void add_to_cache(GdiFont
*font
)
4259 static DWORD cache_num
= 1;
4261 font
->cache_num
= cache_num
++;
4262 list_add_head(&gdi_font_list
, &font
->entry
);
4265 /*************************************************************
4266 * create_child_font_list
4268 static BOOL
create_child_font_list(GdiFont
*font
)
4271 SYSTEM_LINKS
*font_link
;
4272 CHILD_FONT
*font_link_entry
, *new_child
;
4276 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4277 font_name
= psub
? psub
->to
.name
: font
->name
;
4278 font_link
= find_font_link(font_name
);
4279 if (font_link
!= NULL
)
4281 TRACE("found entry in system list\n");
4282 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4284 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4285 new_child
->face
= font_link_entry
->face
;
4286 new_child
->font
= NULL
;
4287 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4288 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
4293 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4294 * Sans Serif. This is how asian windows get default fallbacks for fonts
4296 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4297 font
->charset
!= OEM_CHARSET
&&
4298 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4300 font_link
= find_font_link(szDefaultFallbackLink
);
4301 if (font_link
!= NULL
)
4303 TRACE("found entry in default fallback list\n");
4304 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4306 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4307 new_child
->face
= font_link_entry
->face
;
4308 new_child
->font
= NULL
;
4309 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4310 TRACE("font %s %ld\n", debugstr_a(new_child
->face
->file
), new_child
->face
->face_index
);
4319 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4321 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4323 if (pFT_Set_Charmap
)
4326 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4328 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4330 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4332 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4334 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4335 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4337 switch (ft_face
->charmaps
[i
]->platform_id
)
4340 cmap_def
= ft_face
->charmaps
[i
];
4342 case 0: /* Apple Unicode */
4343 cmap0
= ft_face
->charmaps
[i
];
4345 case 1: /* Macintosh */
4346 cmap1
= ft_face
->charmaps
[i
];
4349 cmap2
= ft_face
->charmaps
[i
];
4351 case 3: /* Microsoft */
4352 cmap3
= ft_face
->charmaps
[i
];
4357 if (cmap3
) /* prefer Microsoft cmap table */
4358 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4360 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4362 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4364 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4366 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4368 return ft_err
== FT_Err_Ok
;
4371 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4375 /*************************************************************
4378 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4379 LPCWSTR output
, const DEVMODEW
*devmode
)
4381 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4383 if (!physdev
) return FALSE
;
4384 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4389 /*************************************************************
4392 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4394 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4395 HeapFree( GetProcessHeap(), 0, physdev
);
4400 /*************************************************************
4401 * freetype_SelectFont
4403 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
)
4405 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4407 Face
*face
, *best
, *best_bitmap
;
4408 Family
*family
, *last_resort_family
;
4409 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
4410 INT height
, width
= 0;
4411 unsigned int score
= 0, new_score
;
4412 signed int diff
= 0, newdiff
;
4413 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4418 FontSubst
*psub
= NULL
;
4419 DC
*dc
= get_dc_ptr( dev
->hdc
);
4420 const SYSTEM_LINKS
*font_link
;
4422 if (!hfont
) /* notification that the font has been changed by another driver */
4425 physdev
->font
= NULL
;
4426 release_dc_ptr( dc
);
4430 GetObjectW( hfont
, sizeof(lf
), &lf
);
4431 lf
.lfWidth
= abs(lf
.lfWidth
);
4433 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4435 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4436 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4437 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4440 if(dc
->GraphicsMode
== GM_ADVANCED
)
4442 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4443 /* Try to avoid not necessary glyph transformations */
4444 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4446 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4447 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4448 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4453 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4454 font scaling abilities. */
4455 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4456 dcmat
.eM21
= dcmat
.eM12
= 0;
4457 if (dc
->vport2WorldValid
)
4459 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4460 lf
.lfOrientation
= -lf
.lfOrientation
;
4461 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4462 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4466 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4467 dcmat
.eM21
, dcmat
.eM22
);
4470 EnterCriticalSection( &freetype_cs
);
4472 /* check the cache first */
4473 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4474 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4478 if(list_empty(&font_list
)) /* No fonts installed */
4480 TRACE("No fonts installed\n");
4484 TRACE("not in cache\n");
4487 ret
->font_desc
.matrix
= dcmat
;
4488 ret
->font_desc
.lf
= lf
;
4489 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4490 calc_hash(&ret
->font_desc
);
4491 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
4492 hflist
->hfont
= hfont
;
4493 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
4495 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4496 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4497 original value lfCharSet. Note this is a special case for
4498 Symbol and doesn't happen at least for "Wingdings*" */
4500 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4501 lf
.lfCharSet
= SYMBOL_CHARSET
;
4503 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4504 switch(lf
.lfCharSet
) {
4505 case DEFAULT_CHARSET
:
4506 csi
.fs
.fsCsb
[0] = 0;
4509 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4510 csi
.fs
.fsCsb
[0] = 0;
4516 if(lf
.lfFaceName
[0] != '\0') {
4517 CHILD_FONT
*font_link_entry
;
4518 LPWSTR FaceName
= lf
.lfFaceName
;
4520 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4523 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4524 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4525 if (psub
->to
.charset
!= -1)
4526 lf
.lfCharSet
= psub
->to
.charset
;
4529 /* We want a match on name and charset or just name if
4530 charset was DEFAULT_CHARSET. If the latter then
4531 we fixup the returned charset later in get_nearest_charset
4532 where we'll either use the charset of the current ansi codepage
4533 or if that's unavailable the first charset that the font supports.
4535 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4536 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4537 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4538 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4540 font_link
= find_font_link(family
->FamilyName
);
4541 face_list
= get_face_list_from_family(family
);
4542 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4543 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4544 if (!(face
->scalable
|| can_use_bitmap
))
4546 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4548 if (font_link
!= NULL
&&
4549 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4551 if (!csi
.fs
.fsCsb
[0])
4557 /* Search by full face name. */
4558 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4559 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4560 face_list
= get_face_list_from_family(family
);
4561 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4562 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4563 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4564 (face
->scalable
|| can_use_bitmap
))
4566 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4568 font_link
= find_font_link(family
->FamilyName
);
4569 if (font_link
!= NULL
&&
4570 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4577 * Try check the SystemLink list first for a replacement font.
4578 * We may find good replacements there.
4580 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4582 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4583 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4585 TRACE("found entry in system list\n");
4586 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4588 const SYSTEM_LINKS
*links
;
4590 face
= font_link_entry
->face
;
4591 if (!(face
->scalable
|| can_use_bitmap
))
4593 family
= face
->family
;
4594 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4596 links
= find_font_link(family
->FamilyName
);
4597 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4604 psub
= NULL
; /* substitution is no more relevant */
4606 /* If requested charset was DEFAULT_CHARSET then try using charset
4607 corresponding to the current ansi codepage */
4608 if (!csi
.fs
.fsCsb
[0])
4611 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4612 FIXME("TCI failed on codepage %d\n", acp
);
4613 csi
.fs
.fsCsb
[0] = 0;
4615 lf
.lfCharSet
= csi
.ciCharset
;
4618 want_vertical
= (lf
.lfFaceName
[0] == '@');
4620 /* Face families are in the top 4 bits of lfPitchAndFamily,
4621 so mask with 0xF0 before testing */
4623 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4624 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4625 strcpyW(lf
.lfFaceName
, defFixed
);
4626 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4627 strcpyW(lf
.lfFaceName
, defSerif
);
4628 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4629 strcpyW(lf
.lfFaceName
, defSans
);
4631 strcpyW(lf
.lfFaceName
, defSans
);
4632 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4633 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4634 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4635 font_link
= find_font_link(family
->FamilyName
);
4636 face_list
= get_face_list_from_family(family
);
4637 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4638 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4639 if (!(face
->scalable
|| can_use_bitmap
))
4641 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4643 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4649 last_resort_family
= NULL
;
4650 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4651 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4652 font_link
= find_font_link(family
->FamilyName
);
4653 face_list
= get_face_list_from_family(family
);
4654 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4655 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4656 if(face
->vertical
== want_vertical
&&
4657 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4658 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4661 if(can_use_bitmap
&& !last_resort_family
)
4662 last_resort_family
= family
;
4667 if(last_resort_family
) {
4668 family
= last_resort_family
;
4669 csi
.fs
.fsCsb
[0] = 0;
4673 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
4674 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
4675 face_list
= get_face_list_from_family(family
);
4676 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
4677 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
4678 if(face
->scalable
&& face
->vertical
== want_vertical
) {
4679 csi
.fs
.fsCsb
[0] = 0;
4680 WARN("just using first face for now\n");
4683 if(can_use_bitmap
&& !last_resort_family
)
4684 last_resort_family
= family
;
4687 if(!last_resort_family
) {
4688 FIXME("can't find a single appropriate font - bailing\n");
4694 WARN("could only find a bitmap font - this will probably look awful!\n");
4695 family
= last_resort_family
;
4696 csi
.fs
.fsCsb
[0] = 0;
4699 it
= lf
.lfItalic
? 1 : 0;
4700 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4702 height
= lf
.lfHeight
;
4704 face
= best
= best_bitmap
= NULL
;
4705 font_link
= find_font_link(family
->FamilyName
);
4706 face_list
= get_face_list_from_family(family
);
4707 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4709 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4710 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4715 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4716 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4717 new_score
= (italic
^ it
) + (bold
^ bd
);
4718 if(!best
|| new_score
<= score
)
4720 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4721 italic
, bold
, it
, bd
);
4724 if(best
->scalable
&& score
== 0) break;
4728 newdiff
= height
- (signed int)(best
->size
.height
);
4730 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4731 if(!best_bitmap
|| new_score
< score
||
4732 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4734 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4737 if(score
== 0 && diff
== 0) break;
4744 face
= best
->scalable
? best
: best_bitmap
;
4745 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
4746 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
4749 height
= lf
.lfHeight
;
4753 if(csi
.fs
.fsCsb
[0]) {
4754 ret
->charset
= lf
.lfCharSet
;
4755 ret
->codepage
= csi
.ciACP
;
4758 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
4760 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
4761 debugstr_w(face
->StyleName
), face
->file
, face
->font_data_ptr
, face
->face_index
);
4763 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
4765 if(!face
->scalable
) {
4766 /* Windows uses integer scaling factors for bitmap fonts */
4767 INT scale
, scaled_height
;
4768 GdiFont
*cachedfont
;
4770 /* FIXME: rotation of bitmap fonts is ignored */
4771 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
4773 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
4774 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4775 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4776 /* As we changed the matrix, we need to search the cache for the font again,
4777 * otherwise we might explode the cache. */
4778 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4779 TRACE("Found cached font after non-scalable matrix rescale!\n");
4784 calc_hash(&ret
->font_desc
);
4786 if (height
!= 0) height
= diff
;
4787 height
+= face
->size
.height
;
4789 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
4790 scaled_height
= scale
* face
->size
.height
;
4791 /* Only jump to the next height if the difference <= 25% original height */
4792 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
4793 /* The jump between unscaled and doubled is delayed by 1 */
4794 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
4795 ret
->scale_y
= scale
;
4797 width
= face
->size
.x_ppem
>> 6;
4798 height
= face
->size
.y_ppem
>> 6;
4802 TRACE("font scale y: %f\n", ret
->scale_y
);
4804 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
4813 ret
->ntmFlags
= face
->ntmFlags
;
4815 if (ret
->charset
== SYMBOL_CHARSET
&&
4816 select_charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
4819 else if (select_charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
4823 select_charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
4826 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
4827 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
4828 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
4829 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
4830 create_child_font_list(ret
);
4832 if (face
->vertical
) /* We need to try to load the GSUB table */
4834 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
4835 if (length
!= GDI_ERROR
)
4837 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
4838 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
4839 TRACE("Loaded GSUB table of %i bytes\n",length
);
4843 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
4850 physdev
->font
= ret
;
4852 LeaveCriticalSection( &freetype_cs
);
4853 release_dc_ptr( dc
);
4854 return ret
? hfont
: 0;
4857 static void dump_gdi_font_list(void)
4860 struct list
*elem_ptr
;
4862 TRACE("---------- gdiFont Cache ----------\n");
4863 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
4864 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4865 TRACE("gdiFont=%p %s %d\n",
4866 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4869 TRACE("---------- Unused gdiFont Cache ----------\n");
4870 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
4871 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4872 TRACE("gdiFont=%p %s %d\n",
4873 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4876 TRACE("---------- Child gdiFont Cache ----------\n");
4877 LIST_FOR_EACH(elem_ptr
, &child_font_list
) {
4878 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
4879 TRACE("gdiFont=%p %s %d\n",
4880 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
4884 /*************************************************************
4885 * WineEngDestroyFontInstance
4887 * free the gdiFont associated with this handle
4890 BOOL
WineEngDestroyFontInstance(HFONT handle
)
4895 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
4899 EnterCriticalSection( &freetype_cs
);
4901 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
4903 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4904 while(hfontlist_elem_ptr
) {
4905 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4906 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4907 if(hflist
->hfont
== handle
) {
4908 TRACE("removing child font %p from child list\n", gdiFont
);
4909 list_remove(&gdiFont
->entry
);
4910 LeaveCriticalSection( &freetype_cs
);
4916 TRACE("destroying hfont=%p\n", handle
);
4918 dump_gdi_font_list();
4920 font_elem_ptr
= list_head(&gdi_font_list
);
4921 while(font_elem_ptr
) {
4922 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4923 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
4925 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
4926 while(hfontlist_elem_ptr
) {
4927 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
4928 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
4929 if(hflist
->hfont
== handle
) {
4930 list_remove(&hflist
->entry
);
4931 HeapFree(GetProcessHeap(), 0, hflist
);
4935 if(list_empty(&gdiFont
->hfontlist
)) {
4936 TRACE("Moving to Unused list\n");
4937 list_remove(&gdiFont
->entry
);
4938 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
4943 font_elem_ptr
= list_head(&unused_gdi_font_list
);
4944 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
4945 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4946 while(font_elem_ptr
) {
4947 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
4948 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
4949 TRACE("freeing %p\n", gdiFont
);
4950 list_remove(&gdiFont
->entry
);
4953 LeaveCriticalSection( &freetype_cs
);
4957 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
4964 id
+= IDS_FIRST_SCRIPT
;
4965 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
4966 if (!rsrc
) return 0;
4967 hMem
= LoadResource( gdi32_module
, rsrc
);
4968 if (!hMem
) return 0;
4970 p
= LockResource( hMem
);
4972 while (id
--) p
+= *p
+ 1;
4974 i
= min(LF_FACESIZE
- 1, *p
);
4975 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
4981 /***************************************************
4982 * create_enum_charset_list
4984 * This function creates charset enumeration list because in DEFAULT_CHARSET
4985 * case, the ANSI codepage's charset takes precedence over other charsets.
4986 * This function works as a filter other than DEFAULT_CHARSET case.
4988 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
4993 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
4994 csi
.fs
.fsCsb
[0] != 0) {
4995 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
4996 list
->element
[n
].charset
= csi
.ciCharset
;
4997 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5000 else { /* charset is DEFAULT_CHARSET or invalid. */
5003 /* Set the current codepage's charset as the first element. */
5005 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5006 csi
.fs
.fsCsb
[0] != 0) {
5007 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5008 list
->element
[n
].charset
= csi
.ciCharset
;
5009 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5013 /* Fill out left elements. */
5014 for (i
= 0; i
< 32; i
++) {
5016 fs
.fsCsb
[0] = 1L << i
;
5018 if (n
> 0 && fs
.fsCsb
[0] == list
->element
[0].mask
)
5019 continue; /* skip, already added. */
5020 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5021 continue; /* skip, this is an invalid fsCsb bit. */
5023 list
->element
[n
].mask
= fs
.fsCsb
[0];
5024 list
->element
[n
].charset
= csi
.ciCharset
;
5025 load_script_name( i
, list
->element
[n
].name
);
5034 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
5035 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5040 if (face
->cached_enum_data
)
5043 *pelf
= face
->cached_enum_data
->elf
;
5044 *pntm
= face
->cached_enum_data
->ntm
;
5045 *ptype
= face
->cached_enum_data
->type
;
5049 font
= alloc_font();
5051 if(face
->scalable
) {
5055 height
= face
->size
.y_ppem
>> 6;
5056 width
= face
->size
.x_ppem
>> 6;
5058 font
->scale_y
= 1.0;
5060 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5066 font
->name
= strdupW(face
->family
->FamilyName
);
5067 font
->ntmFlags
= face
->ntmFlags
;
5069 if (get_outline_text_metrics(font
))
5071 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5073 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5074 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5075 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5077 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5078 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5080 lstrcpynW(pelf
->elfFullName
,
5081 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFullName
),
5083 lstrcpynW(pelf
->elfStyle
,
5084 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5089 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5091 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5092 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5093 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5095 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
5097 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5099 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FULLFACESIZE
);
5100 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5103 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5104 pntm
->ntmFontSig
= face
->fs
;
5106 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5108 pelf
->elfLogFont
.lfEscapement
= 0;
5109 pelf
->elfLogFont
.lfOrientation
= 0;
5110 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5111 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5112 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5113 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5114 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5115 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5116 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5117 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5118 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5119 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5120 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5123 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5124 *ptype
|= TRUETYPE_FONTTYPE
;
5125 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5126 *ptype
|= DEVICE_FONTTYPE
;
5127 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5128 *ptype
|= RASTER_FONTTYPE
;
5130 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5131 if (face
->cached_enum_data
)
5133 face
->cached_enum_data
->elf
= *pelf
;
5134 face
->cached_enum_data
->ntm
= *pntm
;
5135 face
->cached_enum_data
->type
= *ptype
;
5141 static void create_full_name(WCHAR
*full_name
, const WCHAR
*family_name
, const WCHAR
*style_name
)
5143 static const WCHAR spaceW
[] = { ' ', 0 };
5145 strcpyW(full_name
, family_name
);
5146 strcatW(full_name
, spaceW
);
5147 strcatW(full_name
, style_name
);
5150 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5152 const struct list
*face_list
, *face_elem_ptr
;
5154 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5156 face_list
= get_face_list_from_family(family
);
5157 LIST_FOR_EACH(face_elem_ptr
, face_list
)
5159 WCHAR full_family_name
[LF_FULLFACESIZE
];
5160 Face
*face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5162 if (strlenW(family
->FamilyName
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
5164 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5165 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
5169 create_full_name(full_family_name
, family
->FamilyName
, face
->StyleName
);
5170 if (!strcmpiW(lf
->lfFaceName
, full_family_name
)) return TRUE
;
5176 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5178 WCHAR full_family_name
[LF_FULLFACESIZE
];
5180 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5182 if (strlenW(family_name
) + strlenW(face
->StyleName
) + 2 > LF_FULLFACESIZE
)
5184 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5185 debugstr_w(family_name
), debugstr_w(face
->StyleName
));
5189 create_full_name(full_family_name
, family_name
, face
->StyleName
);
5190 return !strcmpiW(lf
->lfFaceName
, full_family_name
);
5193 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5194 FONTENUMPROCW proc
, LPARAM lparam
)
5197 NEWTEXTMETRICEXW ntm
;
5201 GetEnumStructs(face
, &elf
, &ntm
, &type
);
5202 for(i
= 0; i
< list
->total
; i
++) {
5203 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5204 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5205 load_script_name( IDS_OEM_DOS
, elf
.elfScript
);
5206 i
= list
->total
; /* break out of loop after enumeration */
5207 } else if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
))
5210 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5211 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5212 if (!elf
.elfScript
[0])
5213 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5215 /* Font Replacement */
5216 if (family
!= face
->family
)
5218 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5219 create_full_name(elf
.elfFullName
, family
->FamilyName
, face
->StyleName
);
5221 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5222 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5223 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5224 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5225 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5226 ntm
.ntmTm
.ntmFlags
);
5227 /* release section before callback (FIXME) */
5228 LeaveCriticalSection( &freetype_cs
);
5229 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5230 EnterCriticalSection( &freetype_cs
);
5235 /*************************************************************
5236 * freetype_EnumFonts
5238 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5242 const struct list
*family_elem_ptr
, *face_list
, *face_elem_ptr
;
5244 struct enum_charset_list enum_charsets
;
5248 lf
.lfCharSet
= DEFAULT_CHARSET
;
5249 lf
.lfPitchAndFamily
= 0;
5250 lf
.lfFaceName
[0] = 0;
5254 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5256 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5259 EnterCriticalSection( &freetype_cs
);
5260 if(plf
->lfFaceName
[0]) {
5262 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5265 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5266 debugstr_w(psub
->to
.name
));
5268 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5272 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
5273 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
5274 if(family_matches(family
, plf
)) {
5275 face_list
= get_face_list_from_family(family
);
5276 LIST_FOR_EACH(face_elem_ptr
, face_list
) {
5277 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5278 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5279 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5284 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
5285 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
5286 face_list
= get_face_list_from_family(family
);
5287 face_elem_ptr
= list_head(face_list
);
5288 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
5289 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5292 LeaveCriticalSection( &freetype_cs
);
5296 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5298 pt
->x
.value
= vec
->x
>> 6;
5299 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5300 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5301 pt
->y
.value
= vec
->y
>> 6;
5302 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5303 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5307 /***************************************************
5308 * According to the MSDN documentation on WideCharToMultiByte,
5309 * certain codepages cannot set the default_used parameter.
5310 * This returns TRUE if the codepage can set that parameter, false else
5311 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5313 static BOOL
codepage_sets_default_used(UINT codepage
)
5327 * GSUB Table handling functions
5330 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5332 const GSUB_CoverageFormat1
* cf1
;
5336 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5338 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5340 TRACE("Coverage Format 1, %i glyphs\n",count
);
5341 for (i
= 0; i
< count
; i
++)
5342 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5346 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5348 const GSUB_CoverageFormat2
* cf2
;
5351 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5353 count
= GET_BE_WORD(cf2
->RangeCount
);
5354 TRACE("Coverage Format 2, %i ranges\n",count
);
5355 for (i
= 0; i
< count
; i
++)
5357 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5359 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5360 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5362 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5363 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5369 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5374 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5376 const GSUB_ScriptList
*script
;
5377 const GSUB_Script
*deflt
= NULL
;
5379 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5381 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5382 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5384 const GSUB_Script
*scr
;
5387 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5388 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5390 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5392 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5398 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5402 const GSUB_LangSys
*Lang
;
5404 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5406 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5408 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5409 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5411 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5414 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5417 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5423 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5426 const GSUB_FeatureList
*feature
;
5427 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5429 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5430 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5432 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5433 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5435 const GSUB_Feature
*feat
;
5436 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5443 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5447 const GSUB_LookupList
*lookup
;
5448 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5450 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5451 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5453 const GSUB_LookupTable
*look
;
5454 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5455 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5456 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5457 if (GET_BE_WORD(look
->LookupType
) != 1)
5458 FIXME("We only handle SubType 1\n");
5463 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5465 const GSUB_SingleSubstFormat1
*ssf1
;
5466 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5467 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5468 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5470 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5471 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5472 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5474 TRACE(" Glyph 0x%x ->",glyph
);
5475 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5476 TRACE(" 0x%x\n",glyph
);
5481 const GSUB_SingleSubstFormat2
*ssf2
;
5485 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5486 offset
= GET_BE_WORD(ssf1
->Coverage
);
5487 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5488 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5489 TRACE(" Coverage index %i\n",index
);
5492 TRACE(" Glyph is 0x%x ->",glyph
);
5493 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5494 TRACE("0x%x\n",glyph
);
5503 static const char* get_opentype_script(const GdiFont
*font
)
5506 * I am not sure if this is the correct way to generate our script tag
5509 switch (font
->charset
)
5511 case ANSI_CHARSET
: return "latn";
5512 case BALTIC_CHARSET
: return "latn"; /* ?? */
5513 case CHINESEBIG5_CHARSET
: return "hani";
5514 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5515 case GB2312_CHARSET
: return "hani";
5516 case GREEK_CHARSET
: return "grek";
5517 case HANGUL_CHARSET
: return "hang";
5518 case RUSSIAN_CHARSET
: return "cyrl";
5519 case SHIFTJIS_CHARSET
: return "kana";
5520 case TURKISH_CHARSET
: return "latn"; /* ?? */
5521 case VIETNAMESE_CHARSET
: return "latn";
5522 case JOHAB_CHARSET
: return "latn"; /* ?? */
5523 case ARABIC_CHARSET
: return "arab";
5524 case HEBREW_CHARSET
: return "hebr";
5525 case THAI_CHARSET
: return "thai";
5526 default: return "latn";
5530 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5532 const GSUB_Header
*header
;
5533 const GSUB_Script
*script
;
5534 const GSUB_LangSys
*language
;
5535 const GSUB_Feature
*feature
;
5537 if (!font
->GSUB_Table
)
5540 header
= font
->GSUB_Table
;
5542 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5545 TRACE("Script not found\n");
5548 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5551 TRACE("Language not found\n");
5554 feature
= GSUB_get_feature(header
, language
, "vrt2");
5556 feature
= GSUB_get_feature(header
, language
, "vert");
5559 TRACE("vrt2/vert feature not found\n");
5562 return GSUB_apply_feature(header
, feature
, glyph
);
5565 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5569 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5570 WCHAR wc
= (WCHAR
)glyph
;
5572 BOOL
*default_used_pointer
;
5575 default_used_pointer
= NULL
;
5576 default_used
= FALSE
;
5577 if (codepage_sets_default_used(font
->codepage
))
5578 default_used_pointer
= &default_used
;
5579 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5582 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5583 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5587 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5589 if (glyph
< 0x100) glyph
+= 0xf000;
5590 /* there is a number of old pre-Unicode "broken" TTFs, which
5591 do have symbols at U+00XX instead of U+f0XX */
5592 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5593 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5595 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5600 /*************************************************************
5601 * freetype_GetGlyphIndices
5603 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5605 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5608 BOOL got_default
= FALSE
;
5612 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5613 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5616 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5618 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5623 EnterCriticalSection( &freetype_cs
);
5625 for(i
= 0; i
< count
; i
++)
5627 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5632 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5634 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5635 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5640 get_text_metrics(physdev
->font
, &textm
);
5641 default_char
= textm
.tmDefaultChar
;
5645 pgi
[i
] = default_char
;
5648 LeaveCriticalSection( &freetype_cs
);
5652 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5654 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5655 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5658 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5660 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5661 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5664 static inline BYTE
get_max_level( UINT format
)
5668 case GGO_GRAY2_BITMAP
: return 4;
5669 case GGO_GRAY4_BITMAP
: return 16;
5670 case GGO_GRAY8_BITMAP
: return 64;
5675 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5677 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5678 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
5681 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5682 FT_Face ft_face
= incoming_font
->ft_face
;
5683 GdiFont
*font
= incoming_font
;
5684 FT_UInt glyph_index
;
5685 DWORD width
, height
, pitch
, needed
= 0;
5686 FT_Bitmap ft_bitmap
;
5688 INT left
, right
, top
= 0, bottom
= 0, adv
, lsb
, bbx
;
5690 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5691 double widthRatio
= 1.0;
5692 FT_Matrix transMat
= identityMat
;
5693 FT_Matrix transMatUnrotated
;
5694 BOOL needsTransform
= FALSE
;
5695 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5696 UINT original_index
;
5698 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5699 buflen
, buf
, lpmat
);
5701 TRACE("font transform %f %f %f %f\n",
5702 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5703 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5705 if(format
& GGO_GLYPH_INDEX
) {
5706 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5707 original_index
= glyph
;
5708 format
&= ~GGO_GLYPH_INDEX
;
5710 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5711 ft_face
= font
->ft_face
;
5712 original_index
= glyph_index
;
5715 if(format
& GGO_UNHINTED
) {
5716 load_flags
|= FT_LOAD_NO_HINTING
;
5717 format
&= ~GGO_UNHINTED
;
5720 /* tategaki never appears to happen to lower glyph index */
5721 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5724 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5725 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5726 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5727 font
->gmsize
* sizeof(GM
*));
5729 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5730 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5732 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5733 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5734 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5735 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5736 return 1; /* FIXME */
5740 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5741 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5743 /* Scaling factor */
5748 get_text_metrics(font
, &tm
);
5750 widthRatio
= (double)font
->aveWidth
;
5751 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5754 widthRatio
= font
->scale_y
;
5756 /* Scaling transform */
5757 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5760 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5763 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5765 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5766 needsTransform
= TRUE
;
5769 /* Slant transform */
5770 if (font
->fake_italic
) {
5773 slantMat
.xx
= (1 << 16);
5774 slantMat
.xy
= ((1 << 16) >> 2);
5776 slantMat
.yy
= (1 << 16);
5777 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5778 needsTransform
= TRUE
;
5781 /* Rotation transform */
5782 transMatUnrotated
= transMat
;
5783 if(font
->orientation
&& !tategaki
) {
5784 FT_Matrix rotationMat
;
5786 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5787 pFT_Vector_Unit(&vecAngle
, angle
);
5788 rotationMat
.xx
= vecAngle
.x
;
5789 rotationMat
.xy
= -vecAngle
.y
;
5790 rotationMat
.yx
= -rotationMat
.xy
;
5791 rotationMat
.yy
= rotationMat
.xx
;
5793 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5794 needsTransform
= TRUE
;
5797 /* World transform */
5798 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5801 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5802 worldMat
.xy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5803 worldMat
.yx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5804 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5805 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5806 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5807 needsTransform
= TRUE
;
5810 /* Extra transformation specified by caller */
5811 if (!is_identity_MAT2(lpmat
))
5814 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5815 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM12
);
5816 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM21
);
5817 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
5818 pFT_Matrix_Multiply(&extraMat
, &transMat
);
5819 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
5820 needsTransform
= TRUE
;
5823 if (needsTransform
|| (format
== GGO_NATIVE
|| format
== GGO_BEZIER
||
5824 format
== GGO_GRAY2_BITMAP
|| format
== GGO_GRAY4_BITMAP
||
5825 format
== GGO_GRAY8_BITMAP
))
5827 load_flags
|= FT_LOAD_NO_BITMAP
;
5830 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
5833 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
5837 if(!needsTransform
) {
5838 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
5839 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
5840 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
5842 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
5843 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
5844 ft_face
->glyph
->metrics
.height
) & -64;
5845 lpgm
->gmCellIncX
= adv
;
5846 lpgm
->gmCellIncY
= 0;
5853 for(xc
= 0; xc
< 2; xc
++) {
5854 for(yc
= 0; yc
< 2; yc
++) {
5855 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
5856 xc
* ft_face
->glyph
->metrics
.width
);
5857 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
5858 yc
* ft_face
->glyph
->metrics
.height
;
5859 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
5860 pFT_Vector_Transform(&vec
, &transMat
);
5861 if(xc
== 0 && yc
== 0) {
5862 left
= right
= vec
.x
;
5863 top
= bottom
= vec
.y
;
5865 if(vec
.x
< left
) left
= vec
.x
;
5866 else if(vec
.x
> right
) right
= vec
.x
;
5867 if(vec
.y
< bottom
) bottom
= vec
.y
;
5868 else if(vec
.y
> top
) top
= vec
.y
;
5873 right
= (right
+ 63) & -64;
5874 bottom
= bottom
& -64;
5875 top
= (top
+ 63) & -64;
5877 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
5878 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5880 pFT_Vector_Transform(&vec
, &transMat
);
5881 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
5882 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
5884 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
5886 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
5887 adv
= (vec
.x
+63) >> 6;
5891 bbx
= (right
- left
) >> 6;
5892 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
5893 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
5894 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
5895 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
5897 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5898 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5899 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5901 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
5902 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
5904 FONT_GM(font
,original_index
)->gm
= *lpgm
;
5905 FONT_GM(font
,original_index
)->adv
= adv
;
5906 FONT_GM(font
,original_index
)->lsb
= lsb
;
5907 FONT_GM(font
,original_index
)->bbx
= bbx
;
5908 FONT_GM(font
,original_index
)->init
= TRUE
;
5911 if(format
== GGO_METRICS
)
5913 return 1; /* FIXME */
5916 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
5917 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
5919 TRACE("loaded a bitmap\n");
5925 width
= lpgm
->gmBlackBoxX
;
5926 height
= lpgm
->gmBlackBoxY
;
5927 pitch
= ((width
+ 31) >> 5) << 2;
5928 needed
= pitch
* height
;
5930 if(!buf
|| !buflen
) break;
5932 switch(ft_face
->glyph
->format
) {
5933 case ft_glyph_format_bitmap
:
5935 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5936 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
5937 INT h
= ft_face
->glyph
->bitmap
.rows
;
5939 memcpy(dst
, src
, w
);
5940 src
+= ft_face
->glyph
->bitmap
.pitch
;
5946 case ft_glyph_format_outline
:
5947 ft_bitmap
.width
= width
;
5948 ft_bitmap
.rows
= height
;
5949 ft_bitmap
.pitch
= pitch
;
5950 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
5951 ft_bitmap
.buffer
= buf
;
5954 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
5956 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
5958 /* Note: FreeType will only set 'black' bits for us. */
5959 memset(buf
, 0, needed
);
5960 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
5964 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
5969 case GGO_GRAY2_BITMAP
:
5970 case GGO_GRAY4_BITMAP
:
5971 case GGO_GRAY8_BITMAP
:
5972 case WINE_GGO_GRAY16_BITMAP
:
5974 unsigned int max_level
, row
, col
;
5977 width
= lpgm
->gmBlackBoxX
;
5978 height
= lpgm
->gmBlackBoxY
;
5979 pitch
= (width
+ 3) / 4 * 4;
5980 needed
= pitch
* height
;
5982 if(!buf
|| !buflen
) break;
5984 max_level
= get_max_level( format
);
5986 switch(ft_face
->glyph
->format
) {
5987 case ft_glyph_format_bitmap
:
5989 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
5990 INT h
= ft_face
->glyph
->bitmap
.rows
;
5992 memset( buf
, 0, needed
);
5994 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
5995 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
5996 src
+= ft_face
->glyph
->bitmap
.pitch
;
6001 case ft_glyph_format_outline
:
6003 ft_bitmap
.width
= width
;
6004 ft_bitmap
.rows
= height
;
6005 ft_bitmap
.pitch
= pitch
;
6006 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6007 ft_bitmap
.buffer
= buf
;
6010 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6012 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6014 memset(ft_bitmap
.buffer
, 0, buflen
);
6016 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6018 if (max_level
!= 255)
6020 for (row
= 0, start
= buf
; row
< height
; row
++)
6022 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6023 *ptr
= (((int)*ptr
) * max_level
+ 128) / 256;
6031 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6037 case WINE_GGO_HRGB_BITMAP
:
6038 case WINE_GGO_HBGR_BITMAP
:
6039 case WINE_GGO_VRGB_BITMAP
:
6040 case WINE_GGO_VBGR_BITMAP
:
6041 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6043 switch (ft_face
->glyph
->format
)
6045 case FT_GLYPH_FORMAT_BITMAP
:
6050 width
= lpgm
->gmBlackBoxX
;
6051 height
= lpgm
->gmBlackBoxY
;
6053 needed
= pitch
* height
;
6055 if (!buf
|| !buflen
) break;
6057 memset(buf
, 0, buflen
);
6059 src
= ft_face
->glyph
->bitmap
.buffer
;
6060 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6062 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6065 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6067 if ( src
[x
/ 8] & masks
[x
% 8] )
6068 ((unsigned int *)dst
)[x
] = ~0u;
6077 case FT_GLYPH_FORMAT_OUTLINE
:
6081 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6082 INT x_shift
, y_shift
;
6084 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6085 FT_Render_Mode render_mode
=
6086 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6087 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6089 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6091 if ( render_mode
== FT_RENDER_MODE_LCD
)
6093 lpgm
->gmBlackBoxX
+= 2;
6094 lpgm
->gmptGlyphOrigin
.x
-= 1;
6098 lpgm
->gmBlackBoxY
+= 2;
6099 lpgm
->gmptGlyphOrigin
.y
+= 1;
6103 width
= lpgm
->gmBlackBoxX
;
6104 height
= lpgm
->gmBlackBoxY
;
6106 needed
= pitch
* height
;
6108 if (!buf
|| !buflen
) break;
6110 memset(buf
, 0, buflen
);
6112 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6114 if ( needsTransform
)
6115 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6117 if ( pFT_Library_SetLcdFilter
)
6118 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6119 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6121 src
= ft_face
->glyph
->bitmap
.buffer
;
6122 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6123 src_width
= ft_face
->glyph
->bitmap
.width
;
6124 src_height
= ft_face
->glyph
->bitmap
.rows
;
6126 if ( render_mode
== FT_RENDER_MODE_LCD
)
6134 rgb_interval
= src_pitch
;
6139 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6140 if ( x_shift
< 0 ) x_shift
= 0;
6141 if ( x_shift
+ (src_width
/ hmul
) > width
)
6142 x_shift
= width
- (src_width
/ hmul
);
6144 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6145 if ( y_shift
< 0 ) y_shift
= 0;
6146 if ( y_shift
+ (src_height
/ vmul
) > height
)
6147 y_shift
= height
- (src_height
/ vmul
);
6149 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
6150 while ( src_height
)
6152 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
6156 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6157 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6158 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6159 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6163 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6164 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6165 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6166 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6169 src
+= src_pitch
* vmul
;
6178 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6190 int contour
, point
= 0, first_pt
;
6191 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6192 TTPOLYGONHEADER
*pph
;
6194 DWORD pph_start
, cpfx
, type
;
6196 if(buflen
== 0) buf
= NULL
;
6198 if (needsTransform
&& buf
) {
6199 pFT_Outline_Transform(outline
, &transMat
);
6202 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6204 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6207 pph
->dwType
= TT_POLYGON_TYPE
;
6208 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6210 needed
+= sizeof(*pph
);
6212 while(point
<= outline
->contours
[contour
]) {
6213 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6214 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6215 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6219 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6222 } while(point
<= outline
->contours
[contour
] &&
6223 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6224 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6225 /* At the end of a contour Windows adds the start point, but
6227 if(point
> outline
->contours
[contour
] &&
6228 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6230 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6232 } else if(point
<= outline
->contours
[contour
] &&
6233 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6234 /* add closing pt for bezier */
6236 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6244 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6247 pph
->cb
= needed
- pph_start
;
6253 /* Convert the quadratic Beziers to cubic Beziers.
6254 The parametric eqn for a cubic Bezier is, from PLRM:
6255 r(t) = at^3 + bt^2 + ct + r0
6256 with the control points:
6261 A quadratic Bezier has the form:
6262 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6264 So equating powers of t leads to:
6265 r1 = 2/3 p1 + 1/3 p0
6266 r2 = 2/3 p1 + 1/3 p2
6267 and of course r0 = p0, r3 = p2
6270 int contour
, point
= 0, first_pt
;
6271 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6272 TTPOLYGONHEADER
*pph
;
6274 DWORD pph_start
, cpfx
, type
;
6275 FT_Vector cubic_control
[4];
6276 if(buflen
== 0) buf
= NULL
;
6278 if (needsTransform
&& buf
) {
6279 pFT_Outline_Transform(outline
, &transMat
);
6282 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6284 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6287 pph
->dwType
= TT_POLYGON_TYPE
;
6288 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6290 needed
+= sizeof(*pph
);
6292 while(point
<= outline
->contours
[contour
]) {
6293 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6294 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6295 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6298 if(type
== TT_PRIM_LINE
) {
6300 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6304 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6307 /* FIXME: Possible optimization in endpoint calculation
6308 if there are two consecutive curves */
6309 cubic_control
[0] = outline
->points
[point
-1];
6310 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6311 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6312 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6313 cubic_control
[0].x
>>= 1;
6314 cubic_control
[0].y
>>= 1;
6316 if(point
+1 > outline
->contours
[contour
])
6317 cubic_control
[3] = outline
->points
[first_pt
];
6319 cubic_control
[3] = outline
->points
[point
+1];
6320 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6321 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6322 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6323 cubic_control
[3].x
>>= 1;
6324 cubic_control
[3].y
>>= 1;
6327 /* r1 = 1/3 p0 + 2/3 p1
6328 r2 = 1/3 p2 + 2/3 p1 */
6329 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6330 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6331 cubic_control
[2] = cubic_control
[1];
6332 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6333 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6334 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6335 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6337 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6338 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6339 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6344 } while(point
<= outline
->contours
[contour
] &&
6345 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6346 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6347 /* At the end of a contour Windows adds the start point,
6348 but only for Beziers and we've already done that.
6350 if(point
<= outline
->contours
[contour
] &&
6351 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6352 /* This is the closing pt of a bezier, but we've already
6353 added it, so just inc point and carry on */
6360 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6363 pph
->cb
= needed
- pph_start
;
6369 FIXME("Unsupported format %d\n", format
);
6375 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6377 FT_Face ft_face
= font
->ft_face
;
6378 FT_WinFNT_HeaderRec winfnt_header
;
6379 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6380 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6381 font
->potm
->otmSize
= size
;
6383 #define TM font->potm->otmTextMetrics
6384 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6386 TM
.tmHeight
= winfnt_header
.pixel_height
;
6387 TM
.tmAscent
= winfnt_header
.ascent
;
6388 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6389 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6390 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6391 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6392 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6393 TM
.tmWeight
= winfnt_header
.weight
;
6395 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6396 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6397 TM
.tmFirstChar
= winfnt_header
.first_char
;
6398 TM
.tmLastChar
= winfnt_header
.last_char
;
6399 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6400 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6401 TM
.tmItalic
= winfnt_header
.italic
;
6402 TM
.tmUnderlined
= font
->underline
;
6403 TM
.tmStruckOut
= font
->strikeout
;
6404 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6405 TM
.tmCharSet
= winfnt_header
.charset
;
6409 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6410 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6411 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6412 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6413 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6414 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6415 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6416 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6418 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6419 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6421 TM
.tmLastChar
= 255;
6422 TM
.tmDefaultChar
= 32;
6423 TM
.tmBreakChar
= 32;
6424 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6425 TM
.tmUnderlined
= font
->underline
;
6426 TM
.tmStruckOut
= font
->strikeout
;
6427 /* NB inverted meaning of TMPF_FIXED_PITCH */
6428 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6429 TM
.tmCharSet
= font
->charset
;
6437 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6439 double scale_x
, scale_y
;
6443 scale_x
= (double)font
->aveWidth
;
6444 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6447 scale_x
= font
->scale_y
;
6449 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6450 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6452 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6453 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6455 SCALE_Y(ptm
->tmHeight
);
6456 SCALE_Y(ptm
->tmAscent
);
6457 SCALE_Y(ptm
->tmDescent
);
6458 SCALE_Y(ptm
->tmInternalLeading
);
6459 SCALE_Y(ptm
->tmExternalLeading
);
6460 SCALE_Y(ptm
->tmOverhang
);
6462 SCALE_X(ptm
->tmAveCharWidth
);
6463 SCALE_X(ptm
->tmMaxCharWidth
);
6469 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6471 double scale_x
, scale_y
;
6475 scale_x
= (double)font
->aveWidth
;
6476 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6479 scale_x
= font
->scale_y
;
6481 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6482 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6484 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6486 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6487 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6489 SCALE_Y(potm
->otmAscent
);
6490 SCALE_Y(potm
->otmDescent
);
6491 SCALE_Y(potm
->otmLineGap
);
6492 SCALE_Y(potm
->otmsCapEmHeight
);
6493 SCALE_Y(potm
->otmsXHeight
);
6494 SCALE_Y(potm
->otmrcFontBox
.top
);
6495 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6496 SCALE_X(potm
->otmrcFontBox
.left
);
6497 SCALE_X(potm
->otmrcFontBox
.right
);
6498 SCALE_Y(potm
->otmMacAscent
);
6499 SCALE_Y(potm
->otmMacDescent
);
6500 SCALE_Y(potm
->otmMacLineGap
);
6501 SCALE_X(potm
->otmptSubscriptSize
.x
);
6502 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6503 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6504 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6505 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6506 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6507 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6508 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6509 SCALE_Y(potm
->otmsStrikeoutSize
);
6510 SCALE_Y(potm
->otmsStrikeoutPosition
);
6511 SCALE_Y(potm
->otmsUnderscoreSize
);
6512 SCALE_Y(potm
->otmsUnderscorePosition
);
6518 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6522 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6524 /* Make sure that the font has sane width/height ratio */
6527 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6529 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6534 *ptm
= font
->potm
->otmTextMetrics
;
6535 scale_font_metrics(font
, ptm
);
6539 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6543 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6545 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6551 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6554 FT_Face ft_face
= font
->ft_face
;
6555 UINT needed
, lenfam
, lensty
;
6557 TT_HoriHeader
*pHori
;
6558 TT_Postscript
*pPost
;
6559 FT_Fixed x_scale
, y_scale
;
6560 WCHAR
*family_nameW
, *style_nameW
;
6561 static const WCHAR spaceW
[] = {' ', '\0'};
6563 INT ascent
, descent
;
6565 TRACE("font=%p\n", font
);
6567 if(!FT_IS_SCALABLE(ft_face
))
6570 needed
= sizeof(*font
->potm
);
6572 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6573 family_nameW
= strdupW(font
->name
);
6575 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
6577 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
6578 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
6579 style_nameW
, lensty
/sizeof(WCHAR
));
6581 /* These names should be read from the TT name table */
6583 /* length of otmpFamilyName */
6586 /* length of otmpFaceName */
6587 if ((ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) == 0) {
6588 needed
+= lenfam
; /* just the family name */
6590 needed
+= lenfam
+ lensty
; /* family + " " + style */
6593 /* length of otmpStyleName */
6596 /* length of otmpFullName */
6597 needed
+= lenfam
+ lensty
;
6600 x_scale
= ft_face
->size
->metrics
.x_scale
;
6601 y_scale
= ft_face
->size
->metrics
.y_scale
;
6603 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6605 FIXME("Can't find OS/2 table - not TT font?\n");
6609 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6611 FIXME("Can't find HHEA table - not TT font?\n");
6615 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6617 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6618 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6619 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6620 pOS2
->xAvgCharWidth
,
6621 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6622 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6623 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6625 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6626 font
->potm
->otmSize
= needed
;
6628 #define TM font->potm->otmTextMetrics
6630 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6631 ascent
= pHori
->Ascender
;
6632 descent
= -pHori
->Descender
;
6634 ascent
= pOS2
->usWinAscent
;
6635 descent
= pOS2
->usWinDescent
;
6638 font
->ntmCellHeight
= ascent
+ descent
;
6639 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6642 TM
.tmAscent
= font
->yMax
;
6643 TM
.tmDescent
= -font
->yMin
;
6644 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6646 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6647 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6648 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6649 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6652 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6655 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6657 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6658 ((ascent
+ descent
) -
6659 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6661 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6662 if (TM
.tmAveCharWidth
== 0) {
6663 TM
.tmAveCharWidth
= 1;
6665 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6666 TM
.tmWeight
= FW_REGULAR
;
6667 if (font
->fake_bold
)
6668 TM
.tmWeight
= FW_BOLD
;
6671 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6673 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6674 TM
.tmWeight
= pOS2
->usWeightClass
;
6676 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6677 TM
.tmWeight
= pOS2
->usWeightClass
;
6680 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6681 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6682 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6683 * symbol range to 0 - f0ff
6686 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6691 case 1257: /* Baltic */
6692 TM
.tmLastChar
= 0xf8fd;
6695 TM
.tmLastChar
= 0xf0ff;
6697 TM
.tmBreakChar
= 0x20;
6698 TM
.tmDefaultChar
= 0x1f;
6702 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6703 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6705 if(pOS2
->usFirstCharIndex
<= 1)
6706 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6707 else if (pOS2
->usFirstCharIndex
> 0xff)
6708 TM
.tmBreakChar
= 0x20;
6710 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6711 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6713 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6714 TM
.tmUnderlined
= font
->underline
;
6715 TM
.tmStruckOut
= font
->strikeout
;
6717 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6718 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6719 (pOS2
->version
== 0xFFFFU
||
6720 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6721 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6723 TM
.tmPitchAndFamily
= 0;
6725 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6727 case PAN_FAMILY_SCRIPT
:
6728 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6731 case PAN_FAMILY_DECORATIVE
:
6732 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6737 case PAN_FAMILY_TEXT_DISPLAY
:
6738 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6739 /* which is clearly not what the panose spec says. */
6741 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6742 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6743 TM
.tmPitchAndFamily
= FF_MODERN
;
6746 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6751 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6754 case PAN_SERIF_COVE
:
6755 case PAN_SERIF_OBTUSE_COVE
:
6756 case PAN_SERIF_SQUARE_COVE
:
6757 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6758 case PAN_SERIF_SQUARE
:
6759 case PAN_SERIF_THIN
:
6760 case PAN_SERIF_BONE
:
6761 case PAN_SERIF_EXAGGERATED
:
6762 case PAN_SERIF_TRIANGLE
:
6763 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6766 case PAN_SERIF_NORMAL_SANS
:
6767 case PAN_SERIF_OBTUSE_SANS
:
6768 case PAN_SERIF_PERP_SANS
:
6769 case PAN_SERIF_FLARED
:
6770 case PAN_SERIF_ROUNDED
:
6771 TM
.tmPitchAndFamily
|= FF_SWISS
;
6778 if(FT_IS_SCALABLE(ft_face
))
6779 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
6781 if(FT_IS_SFNT(ft_face
))
6783 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
6784 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
6786 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
6789 TM
.tmCharSet
= font
->charset
;
6791 font
->potm
->otmFiller
= 0;
6792 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
6793 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
6794 font
->potm
->otmfsType
= pOS2
->fsType
;
6795 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
6796 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
6797 font
->potm
->otmItalicAngle
= 0; /* POST table */
6798 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
6799 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
6800 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
6801 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
6802 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
6803 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
6804 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6805 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
6806 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
6807 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
6808 font
->potm
->otmMacAscent
= TM
.tmAscent
;
6809 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
6810 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
6811 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
6812 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
6813 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
6814 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
6815 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
6816 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
6817 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
6818 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
6819 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
6820 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
6821 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
6823 font
->potm
->otmsUnderscoreSize
= 0;
6824 font
->potm
->otmsUnderscorePosition
= 0;
6826 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
6827 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
6831 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6832 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
6833 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
6834 strcpyW((WCHAR
*)cp
, family_nameW
);
6836 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
6837 strcpyW((WCHAR
*)cp
, style_nameW
);
6839 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
6840 strcpyW((WCHAR
*)cp
, family_nameW
);
6841 if (ft_face
->style_flags
& (FT_STYLE_FLAG_ITALIC
| FT_STYLE_FLAG_BOLD
)) {
6842 strcatW((WCHAR
*)cp
, spaceW
);
6843 strcatW((WCHAR
*)cp
, style_nameW
);
6844 cp
+= lenfam
+ lensty
;
6847 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
6848 strcpyW((WCHAR
*)cp
, family_nameW
);
6849 strcatW((WCHAR
*)cp
, spaceW
);
6850 strcatW((WCHAR
*)cp
, style_nameW
);
6854 HeapFree(GetProcessHeap(), 0, style_nameW
);
6855 HeapFree(GetProcessHeap(), 0, family_nameW
);
6859 /*************************************************************
6860 * freetype_GetGlyphOutline
6862 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
6863 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
6865 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6870 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
6871 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6875 EnterCriticalSection( &freetype_cs
);
6876 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
6877 LeaveCriticalSection( &freetype_cs
);
6881 /*************************************************************
6882 * freetype_GetTextMetrics
6884 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
6886 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6891 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
6892 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
6896 EnterCriticalSection( &freetype_cs
);
6897 ret
= get_text_metrics( physdev
->font
, metrics
);
6898 LeaveCriticalSection( &freetype_cs
);
6902 /*************************************************************
6903 * freetype_GetOutlineTextMetrics
6905 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
6907 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6912 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
6913 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
6916 TRACE("font=%p\n", physdev
->font
);
6918 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
6921 EnterCriticalSection( &freetype_cs
);
6923 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
6925 if(cbSize
>= physdev
->font
->potm
->otmSize
)
6927 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
6928 scale_outline_font_metrics(physdev
->font
, potm
);
6930 ret
= physdev
->font
->potm
->otmSize
;
6932 LeaveCriticalSection( &freetype_cs
);
6936 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
6938 HFONTLIST
*hfontlist
;
6939 child
->font
= alloc_font();
6940 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
6941 if(!child
->font
->ft_face
)
6943 free_font(child
->font
);
6948 child
->font
->font_desc
= font
->font_desc
;
6949 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
6950 child
->font
->orientation
= font
->orientation
;
6951 child
->font
->scale_y
= font
->scale_y
;
6952 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
6953 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
6954 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
6955 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
6956 child
->font
->base_font
= font
;
6957 list_add_head(&child_font_list
, &child
->font
->entry
);
6958 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
6962 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
6965 CHILD_FONT
*child_font
;
6968 font
= font
->base_font
;
6970 *linked_font
= font
;
6972 if((*glyph
= get_glyph_index(font
, c
)))
6974 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
6978 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
6980 if(!child_font
->font
)
6981 if(!load_child_font(font
, child_font
))
6984 if(!child_font
->font
->ft_face
)
6986 g
= get_glyph_index(child_font
->font
, c
);
6987 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
6991 *linked_font
= child_font
->font
;
6998 /*************************************************************
6999 * freetype_GetCharWidth
7001 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7003 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7006 FT_UInt glyph_index
;
7007 GdiFont
*linked_font
;
7008 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7012 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7013 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7016 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7019 EnterCriticalSection( &freetype_cs
);
7020 for(c
= firstChar
; c
<= lastChar
; c
++) {
7021 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
7022 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7023 &gm
, 0, NULL
, &identity
);
7024 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
7026 LeaveCriticalSection( &freetype_cs
);
7030 /*************************************************************
7031 * freetype_GetCharABCWidths
7033 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7035 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7038 FT_UInt glyph_index
;
7039 GdiFont
*linked_font
;
7040 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7044 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7045 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7048 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7051 EnterCriticalSection( &freetype_cs
);
7053 for(c
= firstChar
; c
<= lastChar
; c
++) {
7054 get_glyph_index_linked(physdev
->font
, c
, &linked_font
, &glyph_index
);
7055 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7056 &gm
, 0, NULL
, &identity
);
7057 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
7058 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
7059 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
7060 FONT_GM(linked_font
,glyph_index
)->bbx
;
7062 LeaveCriticalSection( &freetype_cs
);
7066 /*************************************************************
7067 * freetype_GetCharABCWidthsI
7069 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7071 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7074 FT_UInt glyph_index
;
7075 GdiFont
*linked_font
;
7076 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7080 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7081 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7084 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7088 EnterCriticalSection( &freetype_cs
);
7090 get_glyph_index_linked(physdev
->font
, 'a', &linked_font
, &glyph_index
);
7092 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
7093 get_glyph_outline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7094 &gm
, 0, NULL
, &identity
);
7095 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
7096 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
7097 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
7098 - FONT_GM(linked_font
,c
)->bbx
;
7101 for(c
= 0; c
< count
; c
++) {
7102 get_glyph_outline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7103 &gm
, 0, NULL
, &identity
);
7104 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
7105 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
7106 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
7107 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
7110 LeaveCriticalSection( &freetype_cs
);
7114 /*************************************************************
7115 * freetype_GetTextExtentExPoint
7117 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
,
7118 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
7120 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7125 FT_UInt glyph_index
;
7126 GdiFont
*linked_font
;
7127 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7131 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7132 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, max_ext
, pnfit
, dxs
, size
);
7135 TRACE("%p, %s, %d, %d, %p\n", physdev
->font
, debugstr_wn(wstr
, count
), count
, max_ext
, size
);
7138 EnterCriticalSection( &freetype_cs
);
7141 get_text_metrics( physdev
->font
, &tm
);
7142 size
->cy
= tm
.tmHeight
;
7144 for(idx
= 0; idx
< count
; idx
++) {
7145 get_glyph_index_linked( physdev
->font
, wstr
[idx
], &linked_font
, &glyph_index
);
7146 get_glyph_outline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7147 &gm
, 0, NULL
, &identity
);
7148 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
7150 if (! pnfit
|| ext
<= max_ext
) {
7160 LeaveCriticalSection( &freetype_cs
);
7161 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
7165 /*************************************************************
7166 * freetype_GetTextExtentExPointI
7168 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
,
7169 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
7171 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7176 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7180 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7181 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, max_ext
, pnfit
, dxs
, size
);
7184 TRACE("%p, %p, %d, %d, %p\n", physdev
->font
, indices
, count
, max_ext
, size
);
7187 EnterCriticalSection( &freetype_cs
);
7190 get_text_metrics(physdev
->font
, &tm
);
7191 size
->cy
= tm
.tmHeight
;
7193 for(idx
= 0; idx
< count
; idx
++) {
7194 get_glyph_outline(physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
, &identity
);
7195 size
->cx
+= FONT_GM(physdev
->font
,indices
[idx
])->adv
;
7197 if (! pnfit
|| ext
<= max_ext
) {
7207 LeaveCriticalSection( &freetype_cs
);
7208 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
7212 /*************************************************************
7213 * freetype_GetFontData
7215 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7217 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7221 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7222 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7225 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7226 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7227 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7229 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7232 /*************************************************************
7233 * freetype_GetTextFace
7235 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7238 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7242 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7243 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7246 n
= strlenW(physdev
->font
->name
) + 1;
7249 lstrcpynW(str
, physdev
->font
->name
, count
);
7255 /*************************************************************
7256 * freetype_GetTextCharsetInfo
7258 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7260 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7264 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7265 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7267 if (fs
) *fs
= physdev
->font
->fs
;
7268 return physdev
->font
->charset
;
7271 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7273 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
7274 struct list
*first_hfont
;
7278 EnterCriticalSection( &freetype_cs
);
7279 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
7280 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
7281 if(font
== linked_font
)
7282 *new_hfont
= dc
->hFont
;
7285 first_hfont
= list_head(&linked_font
->hfontlist
);
7286 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
7288 LeaveCriticalSection( &freetype_cs
);
7292 /* Retrieve a list of supported Unicode ranges for a given font.
7293 * Can be called with NULL gs to calculate the buffer size. Returns
7294 * the number of ranges found.
7296 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7298 DWORD num_ranges
= 0;
7300 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7303 FT_ULong char_code
, char_code_prev
;
7306 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7308 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7309 face
->num_glyphs
, glyph_code
, char_code
);
7311 if (!glyph_code
) return 0;
7315 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7316 gs
->ranges
[0].cGlyphs
= 0;
7317 gs
->cGlyphsSupported
= 0;
7323 if (char_code
< char_code_prev
)
7325 ERR("expected increasing char code from FT_Get_Next_Char\n");
7328 if (char_code
- char_code_prev
> 1)
7333 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7334 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7335 gs
->cGlyphsSupported
++;
7340 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7341 gs
->cGlyphsSupported
++;
7343 char_code_prev
= char_code
;
7344 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7348 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7353 /*************************************************************
7354 * freetype_GetFontUnicodeRanges
7356 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7358 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7359 DWORD size
, num_ranges
;
7363 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7364 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7367 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7368 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7371 glyphset
->cbThis
= size
;
7372 glyphset
->cRanges
= num_ranges
;
7373 glyphset
->flAccel
= 0;
7378 /*************************************************************
7379 * freetype_FontIsLinked
7381 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7383 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7388 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7389 return dev
->funcs
->pFontIsLinked( dev
);
7393 EnterCriticalSection( &freetype_cs
);
7394 ret
= !list_empty(&physdev
->font
->child_fonts
);
7395 LeaveCriticalSection( &freetype_cs
);
7399 static BOOL
is_hinting_enabled(void)
7401 /* Use the >= 2.2.0 function if available */
7402 if(pFT_Get_TrueType_Engine_Type
)
7404 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
7405 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
7407 #ifdef FT_DRIVER_HAS_HINTER
7412 /* otherwise if we've been compiled with < 2.2.0 headers
7413 use the internal macro */
7414 mod
= pFT_Get_Module(library
, "truetype");
7415 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
7423 static BOOL
is_subpixel_rendering_enabled( void )
7425 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7426 return pFT_Library_SetLcdFilter
&&
7427 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
;
7433 /*************************************************************************
7434 * GetRasterizerCaps (GDI32.@)
7436 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7438 static int hinting
= -1;
7439 static int subpixel
= -1;
7443 hinting
= is_hinting_enabled();
7444 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
7447 if ( subpixel
== -1 )
7449 subpixel
= is_subpixel_rendering_enabled();
7450 TRACE("subpixel rendering is %senabled\n", subpixel
? "" : "NOT ");
7453 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7454 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
7456 lprs
->wFlags
|= WINE_TT_SUBPIXEL_RENDERING_ENABLED
;
7457 lprs
->nLanguageID
= 0;
7461 /*************************************************************
7462 * freetype_GdiRealizationInfo
7464 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7466 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7467 realization_info_t
*info
= ptr
;
7471 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7472 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7475 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7478 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7481 info
->cache_num
= physdev
->font
->cache_num
;
7482 info
->unknown2
= -1;
7486 /*************************************************************************
7487 * Kerning support for TrueType fonts
7489 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7491 struct TT_kern_table
7497 struct TT_kern_subtable
7506 USHORT horizontal
: 1;
7508 USHORT cross_stream
: 1;
7509 USHORT override
: 1;
7510 USHORT reserved1
: 4;
7516 struct TT_format0_kern_subtable
7520 USHORT entrySelector
;
7531 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7532 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7533 const USHORT
*glyph_to_char
,
7534 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7537 const struct TT_kern_pair
*tt_kern_pair
;
7539 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7541 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7543 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7544 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7545 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7547 if (!kern_pair
|| !cPairs
)
7550 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7552 nPairs
= min(nPairs
, cPairs
);
7554 for (i
= 0; i
< nPairs
; i
++)
7556 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7557 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7558 /* this algorithm appears to better match what Windows does */
7559 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7560 if (kern_pair
->iKernAmount
< 0)
7562 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7563 kern_pair
->iKernAmount
-= font
->ppem
;
7565 else if (kern_pair
->iKernAmount
> 0)
7567 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7568 kern_pair
->iKernAmount
+= font
->ppem
;
7570 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7572 TRACE("left %u right %u value %d\n",
7573 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7577 TRACE("copied %u entries\n", nPairs
);
7581 /*************************************************************
7582 * freetype_GetKerningPairs
7584 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7588 const struct TT_kern_table
*tt_kern_table
;
7589 const struct TT_kern_subtable
*tt_kern_subtable
;
7591 USHORT
*glyph_to_char
;
7593 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7595 if (!(font
= physdev
->font
))
7597 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7598 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7602 EnterCriticalSection( &freetype_cs
);
7603 if (font
->total_kern_pairs
!= (DWORD
)-1)
7605 if (cPairs
&& kern_pair
)
7607 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7608 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7610 else cPairs
= font
->total_kern_pairs
;
7612 LeaveCriticalSection( &freetype_cs
);
7616 font
->total_kern_pairs
= 0;
7618 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7620 if (length
== GDI_ERROR
)
7622 TRACE("no kerning data in the font\n");
7623 LeaveCriticalSection( &freetype_cs
);
7627 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7630 WARN("Out of memory\n");
7631 LeaveCriticalSection( &freetype_cs
);
7635 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7637 /* build a glyph index to char code map */
7638 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7641 WARN("Out of memory allocating a glyph index to char code map\n");
7642 HeapFree(GetProcessHeap(), 0, buf
);
7643 LeaveCriticalSection( &freetype_cs
);
7647 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7653 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7655 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7656 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7660 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7662 /* FIXME: This doesn't match what Windows does: it does some fancy
7663 * things with duplicate glyph index to char code mappings, while
7664 * we just avoid overriding existing entries.
7666 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7667 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7669 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7676 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7677 for (n
= 0; n
<= 65535; n
++)
7678 glyph_to_char
[n
] = (USHORT
)n
;
7681 tt_kern_table
= buf
;
7682 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7683 TRACE("version %u, nTables %u\n",
7684 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7686 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7688 for (i
= 0; i
< nTables
; i
++)
7690 struct TT_kern_subtable tt_kern_subtable_copy
;
7692 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7693 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7694 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7696 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7697 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7698 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7700 /* According to the TrueType specification this is the only format
7701 * that will be properly interpreted by Windows and OS/2
7703 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7705 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7707 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7708 glyph_to_char
, NULL
, 0);
7709 font
->total_kern_pairs
+= new_chunk
;
7711 if (!font
->kern_pairs
)
7712 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7713 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7715 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7716 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7718 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7719 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7722 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7724 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7727 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7728 HeapFree(GetProcessHeap(), 0, buf
);
7730 if (cPairs
&& kern_pair
)
7732 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7733 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7735 else cPairs
= font
->total_kern_pairs
;
7737 LeaveCriticalSection( &freetype_cs
);
7741 static const struct gdi_dc_funcs freetype_funcs
=
7743 NULL
, /* pAbortDoc */
7744 NULL
, /* pAbortPath */
7745 NULL
, /* pAlphaBlend */
7746 NULL
, /* pAngleArc */
7749 NULL
, /* pBeginPath */
7750 NULL
, /* pBlendImage */
7751 NULL
, /* pChoosePixelFormat */
7753 NULL
, /* pCloseFigure */
7754 NULL
, /* pCopyBitmap */
7755 NULL
, /* pCreateBitmap */
7756 NULL
, /* pCreateCompatibleDC */
7757 freetype_CreateDC
, /* pCreateDC */
7758 NULL
, /* pDeleteBitmap */
7759 freetype_DeleteDC
, /* pDeleteDC */
7760 NULL
, /* pDeleteObject */
7761 NULL
, /* pDescribePixelFormat */
7762 NULL
, /* pDeviceCapabilities */
7763 NULL
, /* pEllipse */
7765 NULL
, /* pEndPage */
7766 NULL
, /* pEndPath */
7767 freetype_EnumFonts
, /* pEnumFonts */
7768 NULL
, /* pEnumICMProfiles */
7769 NULL
, /* pExcludeClipRect */
7770 NULL
, /* pExtDeviceMode */
7771 NULL
, /* pExtEscape */
7772 NULL
, /* pExtFloodFill */
7773 NULL
, /* pExtSelectClipRgn */
7774 NULL
, /* pExtTextOut */
7775 NULL
, /* pFillPath */
7776 NULL
, /* pFillRgn */
7777 NULL
, /* pFlattenPath */
7778 freetype_FontIsLinked
, /* pFontIsLinked */
7779 NULL
, /* pFrameRgn */
7780 NULL
, /* pGdiComment */
7781 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7782 NULL
, /* pGetBoundsRect */
7783 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7784 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7785 freetype_GetCharWidth
, /* pGetCharWidth */
7786 NULL
, /* pGetDeviceCaps */
7787 NULL
, /* pGetDeviceGammaRamp */
7788 freetype_GetFontData
, /* pGetFontData */
7789 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7790 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7791 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7792 NULL
, /* pGetICMProfile */
7793 NULL
, /* pGetImage */
7794 freetype_GetKerningPairs
, /* pGetKerningPairs */
7795 NULL
, /* pGetNearestColor */
7796 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7797 NULL
, /* pGetPixel */
7798 NULL
, /* pGetPixelFormat */
7799 NULL
, /* pGetSystemPaletteEntries */
7800 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7801 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7802 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7803 freetype_GetTextFace
, /* pGetTextFace */
7804 freetype_GetTextMetrics
, /* pGetTextMetrics */
7805 NULL
, /* pGradientFill */
7806 NULL
, /* pIntersectClipRect */
7807 NULL
, /* pInvertRgn */
7809 NULL
, /* pModifyWorldTransform */
7811 NULL
, /* pOffsetClipRgn */
7812 NULL
, /* pOffsetViewportOrg */
7813 NULL
, /* pOffsetWindowOrg */
7814 NULL
, /* pPaintRgn */
7817 NULL
, /* pPolyBezier */
7818 NULL
, /* pPolyBezierTo */
7819 NULL
, /* pPolyDraw */
7820 NULL
, /* pPolyPolygon */
7821 NULL
, /* pPolyPolyline */
7822 NULL
, /* pPolygon */
7823 NULL
, /* pPolyline */
7824 NULL
, /* pPolylineTo */
7825 NULL
, /* pPutImage */
7826 NULL
, /* pRealizeDefaultPalette */
7827 NULL
, /* pRealizePalette */
7828 NULL
, /* pRectangle */
7829 NULL
, /* pResetDC */
7830 NULL
, /* pRestoreDC */
7831 NULL
, /* pRoundRect */
7833 NULL
, /* pScaleViewportExt */
7834 NULL
, /* pScaleWindowExt */
7835 NULL
, /* pSelectBitmap */
7836 NULL
, /* pSelectBrush */
7837 NULL
, /* pSelectClipPath */
7838 freetype_SelectFont
, /* pSelectFont */
7839 NULL
, /* pSelectPalette */
7840 NULL
, /* pSelectPen */
7841 NULL
, /* pSetArcDirection */
7842 NULL
, /* pSetBkColor */
7843 NULL
, /* pSetBkMode */
7844 NULL
, /* pSetDCBrushColor */
7845 NULL
, /* pSetDCPenColor */
7846 NULL
, /* pSetDIBColorTable */
7847 NULL
, /* pSetDIBitsToDevice */
7848 NULL
, /* pSetDeviceClipping */
7849 NULL
, /* pSetDeviceGammaRamp */
7850 NULL
, /* pSetLayout */
7851 NULL
, /* pSetMapMode */
7852 NULL
, /* pSetMapperFlags */
7853 NULL
, /* pSetPixel */
7854 NULL
, /* pSetPixelFormat */
7855 NULL
, /* pSetPolyFillMode */
7856 NULL
, /* pSetROP2 */
7857 NULL
, /* pSetRelAbs */
7858 NULL
, /* pSetStretchBltMode */
7859 NULL
, /* pSetTextAlign */
7860 NULL
, /* pSetTextCharacterExtra */
7861 NULL
, /* pSetTextColor */
7862 NULL
, /* pSetTextJustification */
7863 NULL
, /* pSetViewportExt */
7864 NULL
, /* pSetViewportOrg */
7865 NULL
, /* pSetWindowExt */
7866 NULL
, /* pSetWindowOrg */
7867 NULL
, /* pSetWorldTransform */
7868 NULL
, /* pStartDoc */
7869 NULL
, /* pStartPage */
7870 NULL
, /* pStretchBlt */
7871 NULL
, /* pStretchDIBits */
7872 NULL
, /* pStrokeAndFillPath */
7873 NULL
, /* pStrokePath */
7874 NULL
, /* pSwapBuffers */
7875 NULL
, /* pUnrealizePalette */
7876 NULL
, /* pWidenPath */
7877 NULL
, /* pwglCopyContext */
7878 NULL
, /* pwglCreateContext */
7879 NULL
, /* pwglCreateContextAttribsARB */
7880 NULL
, /* pwglDeleteContext */
7881 NULL
, /* pwglGetProcAddress */
7882 NULL
, /* pwglMakeContextCurrentARB */
7883 NULL
, /* pwglMakeCurrent */
7884 NULL
, /* pwglSetPixelFormatWINE */
7885 NULL
, /* pwglShareLists */
7886 NULL
, /* pwglUseFontBitmapsA */
7887 NULL
, /* pwglUseFontBitmapsW */
7888 GDI_PRIORITY_FONT_DRV
/* priority */
7891 #else /* HAVE_FREETYPE */
7893 /*************************************************************************/
7895 BOOL
WineEngInit(void)
7899 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
7904 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7906 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7910 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7912 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7916 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7918 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7922 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
7923 LPCWSTR font_file
, LPCWSTR font_path
)
7929 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
7934 /*************************************************************************
7935 * GetRasterizerCaps (GDI32.@)
7937 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7939 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7941 lprs
->nLanguageID
= 0;
7945 #endif /* HAVE_FREETYPE */