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(FcConfigSubstitute
);
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(FcPatternGetInteger
);
205 MAKE_FUNCPTR(FcPatternGetString
);
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
242 FT_Short internal_leading
;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
249 FT_Short height
, width
;
250 FT_Pos size
, x_ppem
, y_ppem
;
256 NEWTEXTMETRICEXW ntm
;
260 typedef struct tagFace
{
262 unsigned int refcount
;
269 DWORD font_data_size
;
273 FT_Fixed font_version
;
275 Bitmap_Size size
; /* set if face is a bitmap */
276 DWORD flags
; /* ADDFONT flags */
277 struct tagFamily
*family
;
278 /* Cached data for Enum */
279 struct enum_data
*cached_enum_data
;
282 #define ADDFONT_EXTERNAL_FONT 0x01
283 #define ADDFONT_ALLOW_BITMAP 0x02
284 #define ADDFONT_ADD_TO_CACHE 0x04
285 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
286 #define ADDFONT_VERTICAL_FONT 0x10
287 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
289 typedef struct tagFamily
{
291 unsigned int refcount
;
295 struct list
*replacement
;
300 ABC abc
; /* metrics of the unrotated char */
316 typedef struct tagGdiFont GdiFont
;
326 struct list unused_entry
;
327 unsigned int refcount
;
330 OUTLINETEXTMETRICW
*potm
;
331 DWORD total_kern_pairs
;
332 KERNINGPAIR
*kern_pairs
;
333 struct list child_fonts
;
335 /* the following members can be accessed without locking, they are never modified after creation */
337 struct font_mapping
*mapping
;
353 UINT ntmCellHeight
, ntmAvgWidth
;
362 const WCHAR
*font_name
;
367 struct enum_charset_element
{
370 WCHAR name
[LF_FACESIZE
];
373 struct enum_charset_list
{
375 struct enum_charset_element element
[32];
378 #define GM_BLOCK_SIZE 128
379 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
381 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
382 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
383 static unsigned int unused_font_count
;
384 #define UNUSED_CACHE_SIZE 10
385 static struct list system_links
= LIST_INIT(system_links
);
387 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
389 static struct list font_list
= LIST_INIT(font_list
);
391 struct freetype_physdev
393 struct gdi_physdev dev
;
397 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
399 return (struct freetype_physdev
*)dev
;
402 static const struct gdi_dc_funcs freetype_funcs
;
404 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
405 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
406 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
408 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
409 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
410 'W','i','n','d','o','w','s','\\',
411 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
412 'F','o','n','t','s','\0'};
414 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
415 'W','i','n','d','o','w','s',' ','N','T','\\',
416 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
417 'F','o','n','t','s','\0'};
419 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
420 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
421 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
422 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
424 static const WCHAR
* const SystemFontValues
[] = {
431 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
432 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
434 /* Interesting and well-known (frequently-assumed!) font names */
435 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
436 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 };
437 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
438 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
439 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
440 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
441 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
442 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
444 static const WCHAR arial
[] = {'A','r','i','a','l',0};
445 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
446 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};
447 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};
448 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
449 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
450 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
451 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
452 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
453 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
455 static const WCHAR
*default_serif_list
[] =
459 bitstream_vera_serif
,
463 static const WCHAR
*default_fixed_list
[] =
467 bitstream_vera_sans_mono
,
471 static const WCHAR
*default_sans_list
[] =
484 typedef struct tagFontSubst
{
490 /* Registry font cache key and value names */
491 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
492 'F','o','n','t','s',0};
493 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
494 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
495 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
496 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
497 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
498 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
499 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
500 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
501 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
502 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
503 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
504 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
505 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
506 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
507 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
520 static struct list mappings_list
= LIST_INIT( mappings_list
);
522 static UINT default_aa_flags
;
523 static HKEY hkey_font_cache
;
525 static CRITICAL_SECTION freetype_cs
;
526 static CRITICAL_SECTION_DEBUG critsect_debug
=
529 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
530 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
532 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
534 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
536 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
537 static BOOL use_default_fallback
= FALSE
;
539 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
540 static BOOL
get_outline_text_metrics(GdiFont
*font
);
541 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
542 static void remove_face_from_cache( Face
*face
);
544 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
545 'W','i','n','d','o','w','s',' ','N','T','\\',
546 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
547 'S','y','s','t','e','m','L','i','n','k',0};
549 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
550 'F','o','n','t','L','i','n','k','\\',
551 'S','y','s','t','e','m','L','i','n','k',0};
553 /****************************************
554 * Notes on .fon files
556 * The fonts System, FixedSys and Terminal are special. There are typically multiple
557 * versions installed for different resolutions and codepages. Windows stores which one to use
558 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
560 * FIXEDFON.FON FixedSys
562 * OEMFONT.FON Terminal
563 * LogPixels Current dpi set by the display control panel applet
564 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
565 * also has a LogPixels value that appears to mirror this)
567 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
568 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
569 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
570 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
571 * so that makes sense.
573 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
574 * to be mapped into the registry on Windows 2000 at least).
577 * ega80woa.fon=ega80850.fon
578 * ega40woa.fon=ega40850.fon
579 * cga80woa.fon=cga80850.fon
580 * cga40woa.fon=cga40850.fon
583 /* These are all structures needed for the GSUB table */
585 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
586 #define TATEGAKI_LOWER_BOUND 0x02F1
602 GSUB_ScriptRecord ScriptRecord
[1];
608 } GSUB_LangSysRecord
;
613 GSUB_LangSysRecord LangSysRecord
[1];
617 WORD LookupOrder
; /* Reserved */
618 WORD ReqFeatureIndex
;
620 WORD FeatureIndex
[1];
626 } GSUB_FeatureRecord
;
630 GSUB_FeatureRecord FeatureRecord
[1];
634 WORD FeatureParams
; /* Reserved */
636 WORD LookupListIndex
[1];
655 } GSUB_CoverageFormat1
;
660 WORD StartCoverageIndex
;
666 GSUB_RangeRecord RangeRecord
[1];
667 } GSUB_CoverageFormat2
;
670 WORD SubstFormat
; /* = 1 */
673 } GSUB_SingleSubstFormat1
;
676 WORD SubstFormat
; /* = 2 */
680 }GSUB_SingleSubstFormat2
;
682 #ifdef HAVE_CARBON_CARBON_H
683 static char *find_cache_dir(void)
687 static char cached_path
[MAX_PATH
];
688 static const char *wine
= "/Wine", *fonts
= "/Fonts";
690 if(*cached_path
) return cached_path
;
692 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
695 WARN("can't create cached data folder\n");
698 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
701 WARN("can't create cached data path\n");
705 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
707 ERR("Could not create full path\n");
711 strcat(cached_path
, wine
);
713 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
715 WARN("Couldn't mkdir %s\n", cached_path
);
719 strcat(cached_path
, fonts
);
720 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
722 WARN("Couldn't mkdir %s\n", cached_path
);
729 /******************************************************************
732 * Extracts individual TrueType font files from a Mac suitcase font
733 * and saves them into the user's caches directory (see
735 * Returns a NULL terminated array of filenames.
737 * We do this because they are apps that try to read ttf files
738 * themselves and they don't like Mac suitcase files.
740 static char **expand_mac_font(const char *path
)
747 const char *filename
;
751 unsigned int size
, max_size
;
754 TRACE("path %s\n", path
);
756 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
759 WARN("failed to get ref\n");
763 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
766 TRACE("no data fork, so trying resource fork\n");
767 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
770 TRACE("unable to open resource fork\n");
777 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
780 CloseResFile(res_ref
);
784 out_dir
= find_cache_dir();
786 filename
= strrchr(path
, '/');
787 if(!filename
) filename
= path
;
790 /* output filename has the form out_dir/filename_%04x.ttf */
791 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
798 unsigned short *num_faces_ptr
, num_faces
, face
;
801 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
803 fond
= Get1IndResource(fond_res
, idx
);
805 TRACE("got fond resource %d\n", idx
);
808 fam_rec
= *(FamRec
**)fond
;
809 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
810 num_faces
= GET_BE_WORD(*num_faces_ptr
);
812 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
813 TRACE("num faces %04x\n", num_faces
);
814 for(face
= 0; face
< num_faces
; face
++, assoc
++)
817 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
818 unsigned short size
, font_id
;
821 size
= GET_BE_WORD(assoc
->fontSize
);
822 font_id
= GET_BE_WORD(assoc
->fontID
);
825 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
829 TRACE("trying to load sfnt id %04x\n", font_id
);
830 sfnt
= GetResource(sfnt_res
, font_id
);
833 TRACE("can't get sfnt resource %04x\n", font_id
);
837 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
842 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
844 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
845 if(fd
!= -1 || errno
== EEXIST
)
849 unsigned char *sfnt_data
;
852 sfnt_data
= *(unsigned char**)sfnt
;
853 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
857 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
860 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
862 ret
.array
[ret
.size
++] = output
;
866 WARN("unable to create %s\n", output
);
867 HeapFree(GetProcessHeap(), 0, output
);
870 ReleaseResource(sfnt
);
873 ReleaseResource(fond
);
876 CloseResFile(res_ref
);
881 #endif /* HAVE_CARBON_CARBON_H */
883 static inline BOOL
is_win9x(void)
885 return GetVersion() & 0x80000000;
888 This function builds an FT_Fixed from a double. It fails if the absolute
889 value of the float number is greater than 32768.
891 static inline FT_Fixed
FT_FixedFromFloat(double f
)
897 This function builds an FT_Fixed from a FIXED. It simply put f.value
898 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
900 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
902 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
905 static BOOL
is_hinting_enabled(void)
907 static int enabled
= -1;
911 /* Use the >= 2.2.0 function if available */
912 if (pFT_Get_TrueType_Engine_Type
)
914 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
915 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
917 #ifdef FT_DRIVER_HAS_HINTER
920 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
921 FT_Module mod
= pFT_Get_Module(library
, "truetype");
922 enabled
= (mod
&& FT_DRIVER_HAS_HINTER(mod
));
925 else enabled
= FALSE
;
926 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
931 static BOOL
is_subpixel_rendering_enabled( void )
933 #ifdef HAVE_FREETYPE_FTLCDFIL_H
934 static int enabled
= -1;
937 enabled
= (pFT_Library_SetLcdFilter
&&
938 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
939 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
948 static const struct list
*get_face_list_from_family(const Family
*family
)
950 if (!list_empty(&family
->faces
))
951 return &family
->faces
;
953 return family
->replacement
;
956 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
962 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
964 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
966 const struct list
*face_list
;
967 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
969 face_list
= get_face_list_from_family(family
);
970 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
974 file
= strrchrW(face
->file
, '/');
979 if(strcmpiW(file
, file_name
)) continue;
987 static Family
*find_family_from_name(const WCHAR
*name
)
991 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
993 if(!strcmpiW(family
->FamilyName
, name
))
1000 static Family
*find_family_from_any_name(const WCHAR
*name
)
1004 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
1006 if(!strcmpiW(family
->FamilyName
, name
))
1008 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
1015 static void DumpSubstList(void)
1019 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
1021 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
1022 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
1023 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
1025 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1026 debugstr_w(psub
->to
.name
));
1031 static LPWSTR
strdupW(LPCWSTR p
)
1034 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1035 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1036 memcpy(ret
, p
, len
);
1040 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1045 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1047 if(!strcmpiW(element
->from
.name
, from_name
) &&
1048 (element
->from
.charset
== from_charset
||
1049 element
->from
.charset
== -1))
1056 #define ADD_FONT_SUBST_FORCE 1
1058 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1060 FontSubst
*from_exist
, *to_exist
;
1062 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1064 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1066 list_remove(&from_exist
->entry
);
1067 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1068 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1069 HeapFree(GetProcessHeap(), 0, from_exist
);
1075 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1079 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1080 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1083 list_add_tail(subst_list
, &subst
->entry
);
1088 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1089 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1090 HeapFree(GetProcessHeap(), 0, subst
);
1094 static WCHAR
*towstr(UINT cp
, const char *str
)
1099 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1100 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1101 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1105 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1107 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1108 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1109 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1113 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1115 CHAR
*p
= strrchr(str
, ',');
1119 nc
->charset
= strtol(p
+1, NULL
, 10);
1122 nc
->name
= towstr(CP_ACP
, str
);
1125 static void LoadSubstList(void)
1129 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1133 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1134 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1135 &hkey
) == ERROR_SUCCESS
) {
1137 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1138 &valuelen
, &datalen
, NULL
, NULL
);
1140 valuelen
++; /* returned value doesn't include room for '\0' */
1141 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1142 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1146 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1147 &dlen
) == ERROR_SUCCESS
) {
1148 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1150 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1151 split_subst_info(&psub
->from
, value
);
1152 split_subst_info(&psub
->to
, data
);
1154 /* Win 2000 doesn't allow mapping between different charsets
1155 or mapping of DEFAULT_CHARSET */
1156 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1157 psub
->to
.charset
== DEFAULT_CHARSET
) {
1158 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1159 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1160 HeapFree(GetProcessHeap(), 0, psub
);
1162 add_font_subst(&font_subst_list
, psub
, 0);
1164 /* reset dlen and vlen */
1168 HeapFree(GetProcessHeap(), 0, data
);
1169 HeapFree(GetProcessHeap(), 0, value
);
1175 /*****************************************************************
1176 * get_name_table_entry
1178 * Supply the platform, encoding, language and name ids in req
1179 * and if the name exists the function will fill in the string
1180 * and string_len members. The string is owned by FreeType so
1181 * don't free it. Returns TRUE if the name is found else FALSE.
1183 static BOOL
get_name_table_entry(FT_Face ft_face
, FT_SfntName
*req
)
1186 FT_UInt num_names
, name_index
;
1188 if(FT_IS_SFNT(ft_face
))
1190 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
1192 for(name_index
= 0; name_index
< num_names
; name_index
++)
1194 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
1196 if((name
.platform_id
== req
->platform_id
) &&
1197 ((name
.encoding_id
== TT_MS_ID_UNICODE_CS
) || (name
.encoding_id
== TT_MS_ID_SYMBOL_CS
)) &&
1198 (name
.language_id
== req
->language_id
) &&
1199 (name
.name_id
== req
->name_id
))
1201 req
->string
= name
.string
;
1202 req
->string_len
= name
.string_len
;
1209 req
->string_len
= 0;
1213 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, FT_UShort language_id
)
1218 name
.platform_id
= TT_PLATFORM_MICROSOFT
;
1219 name
.language_id
= language_id
;
1220 name
.name_id
= name_id
;
1222 if(get_name_table_entry(ft_face
, &name
))
1226 /* String is not nul terminated and string_len is a byte length. */
1227 ret
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
1228 for(i
= 0; i
< name
.string_len
/ 2; i
++)
1230 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
1231 ret
[i
] = GET_BE_WORD(*tmp
);
1234 TRACE("Got localised name %s\n", debugstr_w(ret
));
1240 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1242 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1243 if (f1
->scalable
) return TRUE
;
1244 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1245 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1248 static void release_family( Family
*family
)
1250 if (--family
->refcount
) return;
1251 assert( list_empty( &family
->faces
));
1252 list_remove( &family
->entry
);
1253 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1254 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1255 HeapFree( GetProcessHeap(), 0, family
);
1258 static void release_face( Face
*face
)
1260 if (--face
->refcount
) return;
1263 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1264 list_remove( &face
->entry
);
1265 release_family( face
->family
);
1267 HeapFree( GetProcessHeap(), 0, face
->file
);
1268 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1269 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1270 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1271 HeapFree( GetProcessHeap(), 0, face
);
1274 static inline int style_order(const Face
*face
)
1276 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1284 case NTM_BOLD
| NTM_ITALIC
:
1287 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1288 debugstr_w(face
->family
->FamilyName
),
1289 debugstr_w(face
->StyleName
),
1295 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1299 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1301 if (faces_equal( face
, cursor
))
1303 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1304 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1305 cursor
->font_version
, face
->font_version
);
1307 if (face
->font_version
<= cursor
->font_version
)
1309 TRACE("Original font %s is newer so skipping %s\n",
1310 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1315 TRACE("Replacing original %s with %s\n",
1316 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1317 list_add_before( &cursor
->entry
, &face
->entry
);
1318 face
->family
= family
;
1321 release_face( cursor
);
1326 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1328 if (style_order( face
) < style_order( cursor
)) break;
1331 list_add_before( &cursor
->entry
, &face
->entry
);
1332 face
->family
= family
;
1338 /****************************************************************
1339 * NB This function stores the ptrs to the strings to save copying.
1340 * Don't free them after calling.
1342 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1344 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1345 family
->refcount
= 1;
1346 family
->FamilyName
= name
;
1347 family
->EnglishName
= english_name
;
1348 list_init( &family
->faces
);
1349 family
->replacement
= &family
->faces
;
1350 list_add_tail( &font_list
, &family
->entry
);
1355 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1357 DWORD type
, size
= sizeof(DWORD
);
1359 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1360 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1363 return ERROR_BAD_CONFIGURATION
;
1365 return ERROR_SUCCESS
;
1368 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1370 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1373 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1375 DWORD needed
, strike_index
= 0;
1378 /* If we have a File Name key then this is a real font, not just the parent
1379 key of a bunch of non-scalable strikes */
1380 needed
= buffer_size
;
1381 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1384 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1385 face
->cached_enum_data
= NULL
;
1386 face
->family
= NULL
;
1389 face
->file
= strdupW( buffer
);
1390 face
->StyleName
= strdupW(face_name
);
1392 needed
= buffer_size
;
1393 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1394 face
->FullName
= strdupW( buffer
);
1396 face
->FullName
= NULL
;
1398 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1399 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1400 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1401 reg_load_dword(hkey_face
, face_flags_value
, (DWORD
*)&face
->flags
);
1403 needed
= sizeof(face
->fs
);
1404 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1406 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1408 face
->scalable
= TRUE
;
1409 memset(&face
->size
, 0, sizeof(face
->size
));
1413 face
->scalable
= FALSE
;
1414 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1415 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1416 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1417 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1418 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1420 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1421 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1422 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1425 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1426 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1427 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1428 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1430 if (insert_face_in_family_list(face
, family
))
1431 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1433 release_face( face
);
1436 /* load bitmap strikes */
1438 needed
= buffer_size
;
1439 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1441 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1443 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1444 RegCloseKey(hkey_strike
);
1446 needed
= buffer_size
;
1450 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1452 DWORD size
, family_index
= 0;
1457 size
= sizeof(buffer
);
1458 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1460 WCHAR
*english_family
= NULL
;
1461 WCHAR
*family_name
= strdupW( buffer
);
1462 DWORD face_index
= 0;
1464 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1465 TRACE("opened family key %s\n", debugstr_w(family_name
));
1466 size
= sizeof(buffer
);
1467 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1468 english_family
= strdupW( buffer
);
1470 family
= create_family(family_name
, english_family
);
1474 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1475 subst
->from
.name
= strdupW(english_family
);
1476 subst
->from
.charset
= -1;
1477 subst
->to
.name
= strdupW(family_name
);
1478 subst
->to
.charset
= -1;
1479 add_font_subst(&font_subst_list
, subst
, 0);
1482 size
= sizeof(buffer
);
1483 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1485 WCHAR
*face_name
= strdupW( buffer
);
1488 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1490 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1491 RegCloseKey(hkey_face
);
1493 HeapFree( GetProcessHeap(), 0, face_name
);
1494 size
= sizeof(buffer
);
1496 RegCloseKey(hkey_family
);
1497 release_family( family
);
1498 size
= sizeof(buffer
);
1502 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1505 HKEY hkey_wine_fonts
;
1507 /* We don't want to create the fonts key as volatile, so open this first */
1508 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1509 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1510 if(ret
!= ERROR_SUCCESS
)
1512 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1516 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1517 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1518 RegCloseKey(hkey_wine_fonts
);
1522 static void add_face_to_cache(Face
*face
)
1524 HKEY hkey_family
, hkey_face
;
1525 WCHAR
*face_key_name
;
1527 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1528 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1529 if(face
->family
->EnglishName
)
1530 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1531 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1534 face_key_name
= face
->StyleName
;
1537 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1538 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1539 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1541 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1544 HeapFree(GetProcessHeap(), 0, face_key_name
);
1546 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1547 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1549 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1550 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1552 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1553 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1554 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1555 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1557 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1561 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1562 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1563 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1564 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1565 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1566 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1568 RegCloseKey(hkey_face
);
1569 RegCloseKey(hkey_family
);
1572 static void remove_face_from_cache( Face
*face
)
1576 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1580 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1584 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1585 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1586 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1587 RegDeleteKeyW( hkey_family
, face_key_name
);
1588 HeapFree(GetProcessHeap(), 0, face_key_name
);
1590 RegCloseKey(hkey_family
);
1593 static WCHAR
*prepend_at(WCHAR
*family
)
1600 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1602 strcpyW(str
+ 1, family
);
1603 HeapFree(GetProcessHeap(), 0, family
);
1607 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1609 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1610 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1612 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1618 else if (!strcmpiW( *name
, *english
))
1620 HeapFree( GetProcessHeap(), 0, *english
);
1626 *name
= prepend_at( *name
);
1627 *english
= prepend_at( *english
);
1631 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1634 WCHAR
*name
, *english_name
;
1636 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1638 family
= find_family_from_name( name
);
1642 family
= create_family( name
, english_name
);
1645 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1646 subst
->from
.name
= strdupW( english_name
);
1647 subst
->from
.charset
= -1;
1648 subst
->to
.name
= strdupW( name
);
1649 subst
->to
.charset
= -1;
1650 add_font_subst( &font_subst_list
, subst
, 0 );
1655 HeapFree( GetProcessHeap(), 0, name
);
1656 HeapFree( GetProcessHeap(), 0, english_name
);
1663 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1665 FT_Fixed version
= 0;
1668 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1669 if (header
) version
= header
->Font_Revision
;
1674 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1677 FT_ULong table_size
= 0;
1679 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1680 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1681 if (flags
== 0) flags
= NTM_REGULAR
;
1683 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1684 flags
|= NTM_PS_OPENTYPE
;
1689 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1691 int internal_leading
= 0;
1692 FT_WinFNT_HeaderRec winfnt_header
;
1694 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1695 internal_leading
= winfnt_header
.internal_leading
;
1697 return internal_leading
;
1700 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1705 FT_WinFNT_HeaderRec winfnt_header
;
1708 memset( fs
, 0, sizeof(*fs
) );
1710 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1713 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1714 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1715 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1716 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1718 if (os2
->version
== 0)
1720 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1721 fs
->fsCsb
[0] = FS_LATIN1
;
1723 fs
->fsCsb
[0] = FS_SYMBOL
;
1727 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1728 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1733 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1735 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1736 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1737 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1742 if (fs
->fsCsb
[0] == 0)
1744 /* let's see if we can find any interesting cmaps */
1745 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1747 switch (ft_face
->charmaps
[i
]->encoding
)
1749 case FT_ENCODING_UNICODE
:
1750 case FT_ENCODING_APPLE_ROMAN
:
1751 fs
->fsCsb
[0] |= FS_LATIN1
;
1753 case FT_ENCODING_MS_SYMBOL
:
1754 fs
->fsCsb
[0] |= FS_SYMBOL
;
1763 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1767 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1768 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1771 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1772 if (!face
->StyleName
)
1773 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1774 if (!face
->StyleName
)
1776 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1779 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1780 if (!face
->FullName
)
1781 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1782 if (flags
& ADDFONT_VERTICAL_FONT
)
1783 face
->FullName
= prepend_at( face
->FullName
);
1789 face
->file
= towstr( CP_UNIXCP
, file
);
1790 face
->font_data_ptr
= NULL
;
1791 face
->font_data_size
= 0;
1792 if (!stat( file
, &st
))
1794 face
->dev
= st
.st_dev
;
1795 face
->ino
= st
.st_ino
;
1801 face
->font_data_ptr
= font_data_ptr
;
1802 face
->font_data_size
= font_data_size
;
1805 face
->face_index
= face_index
;
1806 get_fontsig( ft_face
, &face
->fs
);
1807 face
->ntmFlags
= get_ntm_flags( ft_face
);
1808 face
->font_version
= get_font_version( ft_face
);
1810 if (FT_IS_SCALABLE( ft_face
))
1812 memset( &face
->size
, 0, sizeof(face
->size
) );
1813 face
->scalable
= TRUE
;
1817 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1818 size
->height
, size
->width
, size
->size
>> 6,
1819 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1820 face
->size
.height
= size
->height
;
1821 face
->size
.width
= size
->width
;
1822 face
->size
.size
= size
->size
;
1823 face
->size
.x_ppem
= size
->x_ppem
;
1824 face
->size
.y_ppem
= size
->y_ppem
;
1825 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1826 face
->scalable
= FALSE
;
1829 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1830 face
->flags
= flags
;
1831 face
->family
= NULL
;
1832 face
->cached_enum_data
= NULL
;
1834 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1835 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1836 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1837 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1842 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1843 FT_Long face_index
, DWORD flags
)
1848 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
1849 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
1850 if (insert_face_in_family_list( face
, family
))
1852 if (flags
& ADDFONT_ADD_TO_CACHE
)
1853 add_face_to_cache( face
);
1855 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1856 debugstr_w(face
->StyleName
));
1858 release_face( face
);
1859 release_family( family
);
1862 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1863 FT_Long face_index
, BOOL allow_bitmap
)
1871 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1872 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1876 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1877 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1882 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1886 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1887 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1889 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1893 if (!FT_IS_SFNT( ft_face
))
1895 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1897 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1903 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1904 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1905 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1907 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1908 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1912 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1913 we don't want to load these. */
1914 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1918 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1920 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1926 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1928 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1934 pFT_Done_Face( ft_face
);
1938 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1941 FT_Long face_index
= 0, num_faces
;
1944 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1945 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1947 #ifdef HAVE_CARBON_CARBON_H
1950 char **mac_list
= expand_mac_font(file
);
1953 BOOL had_one
= FALSE
;
1955 for(cursor
= mac_list
; *cursor
; cursor
++)
1958 AddFontToList(*cursor
, NULL
, 0, flags
);
1959 HeapFree(GetProcessHeap(), 0, *cursor
);
1961 HeapFree(GetProcessHeap(), 0, mac_list
);
1966 #endif /* HAVE_CARBON_CARBON_H */
1969 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
1970 if (!ft_face
) return 0;
1972 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1974 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1975 pFT_Done_Face(ft_face
);
1979 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
1982 if (FT_HAS_VERTICAL(ft_face
))
1984 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
1985 flags
| ADDFONT_VERTICAL_FONT
);
1989 num_faces
= ft_face
->num_faces
;
1990 pFT_Done_Face(ft_face
);
1991 } while(num_faces
> ++face_index
);
1995 static int remove_font_resource( const char *file
, DWORD flags
)
1997 Family
*family
, *family_next
;
1998 Face
*face
, *face_next
;
2002 if (stat( file
, &st
) == -1) return 0;
2003 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2006 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2008 if (!face
->file
) continue;
2009 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2010 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2012 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2013 release_face( face
);
2017 release_family( family
);
2022 static void DumpFontList(void)
2027 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2028 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2029 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2030 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2032 TRACE(" %d", face
->size
.height
);
2039 /***********************************************************
2040 * The replacement list is a way to map an entire font
2041 * family onto another family. For example adding
2043 * [HKCU\Software\Wine\Fonts\Replacements]
2044 * "Wingdings"="Winedings"
2046 * would enumerate the Winedings font both as Winedings and
2047 * Wingdings. However if a real Wingdings font is present the
2048 * replacement does not take place.
2051 static void LoadReplaceList(void)
2054 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2058 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2059 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2061 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2062 &valuelen
, &datalen
, NULL
, NULL
);
2064 valuelen
++; /* returned value doesn't include room for '\0' */
2065 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2066 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2070 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2071 &dlen
) == ERROR_SUCCESS
) {
2072 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2073 /* "NewName"="Oldname" */
2074 if(!find_family_from_any_name(value
))
2076 Family
* const family
= find_family_from_any_name(data
);
2079 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2080 if (new_family
!= NULL
)
2082 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2083 new_family
->FamilyName
= strdupW(value
);
2084 new_family
->EnglishName
= NULL
;
2085 list_init(&new_family
->faces
);
2086 new_family
->replacement
= &family
->faces
;
2087 list_add_tail(&font_list
, &new_family
->entry
);
2092 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2097 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2099 /* reset dlen and vlen */
2103 HeapFree(GetProcessHeap(), 0, data
);
2104 HeapFree(GetProcessHeap(), 0, value
);
2109 static const WCHAR
*font_links_list
[] =
2111 Lucida_Sans_Unicode
,
2112 Microsoft_Sans_Serif
,
2116 static const struct font_links_defaults_list
2118 /* Keyed off substitution for "MS Shell Dlg" */
2119 const WCHAR
*shelldlg
;
2120 /* Maximum of four substitutes, plus terminating NULL pointer */
2121 const WCHAR
*substitutes
[5];
2122 } font_links_defaults_list
[] =
2124 /* Non East-Asian */
2125 { Tahoma
, /* FIXME unverified ordering */
2126 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2128 /* Below lists are courtesy of
2129 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2133 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2135 /* Chinese Simplified */
2137 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2141 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2143 /* Chinese Traditional */
2145 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2150 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2152 SYSTEM_LINKS
*font_link
;
2154 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2156 if(!strcmpiW(font_link
->font_name
, name
))
2163 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2174 SYSTEM_LINKS
*font_link
;
2176 psub
= get_font_subst(&font_subst_list
, name
, -1);
2177 /* Don't store fonts that are only substitutes for other fonts */
2180 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2184 font_link
= find_font_link(name
);
2185 if (font_link
== NULL
)
2187 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2188 font_link
->font_name
= strdupW(name
);
2189 list_init(&font_link
->links
);
2190 list_add_tail(&system_links
, &font_link
->entry
);
2193 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2194 for (i
= 0; values
[i
] != NULL
; i
++)
2196 const struct list
*face_list
;
2197 CHILD_FONT
*child_font
;
2200 if (!strcmpiW(name
,value
))
2202 psub
= get_font_subst(&font_subst_list
, value
, -1);
2204 value
= psub
->to
.name
;
2205 family
= find_family_from_name(value
);
2209 /* Use first extant filename for this Family */
2210 face_list
= get_face_list_from_family(family
);
2211 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2215 file
= strrchrW(face
->file
, '/');
2224 face
= find_face_from_filename(file
, value
);
2227 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2231 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2232 child_font
->face
= face
;
2233 child_font
->font
= NULL
;
2234 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2235 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2236 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2237 child_font
->face
->face_index
);
2238 list_add_tail(&font_link
->links
, &child_font
->entry
);
2240 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2246 /*************************************************************
2249 static BOOL
init_system_links(void)
2253 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2254 WCHAR
*value
, *data
;
2255 WCHAR
*entry
, *next
;
2256 SYSTEM_LINKS
*font_link
, *system_font_link
;
2257 CHILD_FONT
*child_font
;
2258 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2259 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2260 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2265 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2267 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2268 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2269 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2270 val_len
= max_val
+ 1;
2271 data_len
= max_data
;
2273 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2275 psub
= get_font_subst(&font_subst_list
, value
, -1);
2276 /* Don't store fonts that are only substitutes for other fonts */
2279 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2282 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2283 font_link
->font_name
= strdupW(value
);
2284 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2285 list_init(&font_link
->links
);
2286 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2289 CHILD_FONT
*child_font
;
2291 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2293 next
= entry
+ strlenW(entry
) + 1;
2295 face_name
= strchrW(entry
, ',');
2299 while(isspaceW(*face_name
))
2302 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2304 face_name
= psub
->to
.name
;
2306 face
= find_face_from_filename(entry
, face_name
);
2309 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2313 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2314 child_font
->face
= face
;
2315 child_font
->font
= NULL
;
2316 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2317 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2318 TRACE("Adding file %s index %ld\n",
2319 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2320 list_add_tail(&font_link
->links
, &child_font
->entry
);
2322 list_add_tail(&system_links
, &font_link
->entry
);
2324 val_len
= max_val
+ 1;
2325 data_len
= max_data
;
2328 HeapFree(GetProcessHeap(), 0, value
);
2329 HeapFree(GetProcessHeap(), 0, data
);
2334 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2336 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2340 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2342 const FontSubst
*psub2
;
2343 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2345 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2347 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2348 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2350 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2351 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2353 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2355 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2361 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2364 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2365 system_font_link
->font_name
= strdupW(System
);
2366 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2367 list_init(&system_font_link
->links
);
2369 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2372 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2373 child_font
->face
= face
;
2374 child_font
->font
= NULL
;
2375 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2376 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2377 TRACE("Found Tahoma in %s index %ld\n",
2378 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2379 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2381 font_link
= find_font_link(Tahoma
);
2382 if (font_link
!= NULL
)
2384 CHILD_FONT
*font_link_entry
;
2385 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2387 CHILD_FONT
*new_child
;
2388 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2389 new_child
->face
= font_link_entry
->face
;
2390 new_child
->font
= NULL
;
2391 new_child
->face
->refcount
++;
2392 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2393 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2394 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2397 list_add_tail(&system_links
, &system_font_link
->entry
);
2401 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2404 struct dirent
*dent
;
2405 char path
[MAX_PATH
];
2407 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2409 dir
= opendir(dirname
);
2411 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2414 while((dent
= readdir(dir
)) != NULL
) {
2415 struct stat statbuf
;
2417 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2420 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2422 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2424 if(stat(path
, &statbuf
) == -1)
2426 WARN("Can't stat %s\n", debugstr_a(path
));
2429 if(S_ISDIR(statbuf
.st_mode
))
2430 ReadFontDir(path
, external_fonts
);
2433 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2434 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2435 AddFontToList(path
, NULL
, 0, addfont_flags
);
2442 #ifdef SONAME_LIBFONTCONFIG
2444 static BOOL fontconfig_enabled
;
2446 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2452 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2453 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2455 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2459 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2460 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2461 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2462 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2463 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2469 static void init_fontconfig(void)
2471 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2475 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2479 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2480 LOAD_FUNCPTR(FcConfigSubstitute
);
2481 LOAD_FUNCPTR(FcFontList
);
2482 LOAD_FUNCPTR(FcFontSetDestroy
);
2483 LOAD_FUNCPTR(FcInit
);
2484 LOAD_FUNCPTR(FcObjectSetAdd
);
2485 LOAD_FUNCPTR(FcObjectSetCreate
);
2486 LOAD_FUNCPTR(FcObjectSetDestroy
);
2487 LOAD_FUNCPTR(FcPatternCreate
);
2488 LOAD_FUNCPTR(FcPatternDestroy
);
2489 LOAD_FUNCPTR(FcPatternGetBool
);
2490 LOAD_FUNCPTR(FcPatternGetInteger
);
2491 LOAD_FUNCPTR(FcPatternGetString
);
2496 FcPattern
*pattern
= pFcPatternCreate();
2497 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2498 default_aa_flags
= parse_aa_pattern( pattern
);
2499 pFcPatternDestroy( pattern
);
2500 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2501 fontconfig_enabled
= TRUE
;
2505 static void load_fontconfig_fonts(void)
2514 if (!fontconfig_enabled
) return;
2516 pat
= pFcPatternCreate();
2517 os
= pFcObjectSetCreate();
2518 pFcObjectSetAdd(os
, FC_FILE
);
2519 pFcObjectSetAdd(os
, FC_SCALABLE
);
2520 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2521 pFcObjectSetAdd(os
, FC_RGBA
);
2522 fontset
= pFcFontList(NULL
, pat
, os
);
2523 if(!fontset
) return;
2524 for(i
= 0; i
< fontset
->nfont
; i
++) {
2528 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2531 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2533 /* We're just interested in OT/TT fonts for now, so this hack just
2534 picks up the scalable fonts without extensions .pf[ab] to save time
2535 loading every other font */
2537 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2539 TRACE("not scalable\n");
2543 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2544 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2546 len
= strlen( file
);
2547 if(len
< 4) continue;
2548 ext
= &file
[ len
- 3 ];
2549 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2550 AddFontToList(file
, NULL
, 0,
2551 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2553 pFcFontSetDestroy(fontset
);
2554 pFcObjectSetDestroy(os
);
2555 pFcPatternDestroy(pat
);
2558 #elif defined(HAVE_CARBON_CARBON_H)
2560 static void load_mac_font_callback(const void *value
, void *context
)
2562 CFStringRef pathStr
= value
;
2566 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2567 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2568 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2570 TRACE("font file %s\n", path
);
2571 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2573 HeapFree(GetProcessHeap(), 0, path
);
2576 static void load_mac_fonts(void)
2578 CFStringRef removeDupesKey
;
2579 CFBooleanRef removeDupesValue
;
2580 CFDictionaryRef options
;
2581 CTFontCollectionRef col
;
2583 CFMutableSetRef paths
;
2586 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2587 removeDupesValue
= kCFBooleanTrue
;
2588 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2589 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2590 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2591 if (options
) CFRelease(options
);
2594 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2598 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2602 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2606 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2609 WARN("CFSetCreateMutable failed\n");
2614 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2616 CTFontDescriptorRef desc
;
2625 desc
= CFArrayGetValueAtIndex(descs
, i
);
2627 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2628 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2629 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2630 if (!font
) continue;
2632 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2639 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2641 if (status
!= noErr
) continue;
2643 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2646 ext
= CFURLCopyPathExtension(url
);
2649 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2650 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2659 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2661 if (!path
) continue;
2663 CFSetAddValue(paths
, path
);
2669 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2675 static char *get_data_dir_path( LPCWSTR file
)
2677 char *unix_name
= NULL
;
2678 const char *data_dir
= wine_get_data_dir();
2680 if (!data_dir
) data_dir
= wine_get_build_dir();
2684 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2686 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2687 strcpy(unix_name
, data_dir
);
2688 strcat(unix_name
, "/fonts/");
2690 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2695 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2698 char *unix_name
= get_data_dir_path( file
);
2702 EnterCriticalSection( &freetype_cs
);
2703 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2704 LeaveCriticalSection( &freetype_cs
);
2705 HeapFree(GetProcessHeap(), 0, unix_name
);
2710 static char *get_winfonts_dir_path(LPCWSTR file
)
2712 static const WCHAR slashW
[] = {'\\','\0'};
2713 WCHAR windowsdir
[MAX_PATH
];
2715 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2716 strcatW(windowsdir
, fontsW
);
2717 strcatW(windowsdir
, slashW
);
2718 strcatW(windowsdir
, file
);
2719 return wine_get_unix_file_name( windowsdir
);
2722 static void load_system_fonts(void)
2725 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2726 const WCHAR
* const *value
;
2728 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2731 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2732 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2733 strcatW(windowsdir
, fontsW
);
2734 for(value
= SystemFontValues
; *value
; value
++) {
2735 dlen
= sizeof(data
);
2736 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2740 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2741 if((unixname
= wine_get_unix_file_name(pathW
))) {
2742 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2743 HeapFree(GetProcessHeap(), 0, unixname
);
2746 load_font_from_data_dir(data
);
2753 /*************************************************************
2755 * This adds registry entries for any externally loaded fonts
2756 * (fonts from fontconfig or FontDirs). It also deletes entries
2757 * of no longer existing fonts.
2760 static void update_reg_entries(void)
2762 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2768 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2770 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2771 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2772 ERR("Can't create Windows font reg key\n");
2776 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2777 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2778 ERR("Can't create Windows font reg key\n");
2782 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2783 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2784 ERR("Can't create external font reg key\n");
2788 /* enumerate the fonts and add external ones to the two keys */
2790 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2791 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2793 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
2797 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2798 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2799 strcpyW(valueW
, face
->FullName
);
2803 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2804 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2805 strcpyW(valueW
, family
->FamilyName
);
2808 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
2809 path
= wine_get_dos_file_name( buffer
);
2810 HeapFree( GetProcessHeap(), 0, buffer
);
2814 else if ((file
= strrchrW(face
->file
, '/')))
2819 len
= strlenW(file
) + 1;
2820 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2821 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2822 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2824 HeapFree(GetProcessHeap(), 0, path
);
2825 HeapFree(GetProcessHeap(), 0, valueW
);
2829 if(external_key
) RegCloseKey(external_key
);
2830 if(win9x_key
) RegCloseKey(win9x_key
);
2831 if(winnt_key
) RegCloseKey(winnt_key
);
2835 static void delete_external_font_keys(void)
2837 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2838 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2842 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2843 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2844 ERR("Can't create Windows font reg key\n");
2848 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2849 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2850 ERR("Can't create Windows font reg key\n");
2854 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2855 ERR("Can't create external font reg key\n");
2859 /* Delete all external fonts added last time */
2861 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2862 &valuelen
, &datalen
, NULL
, NULL
);
2863 valuelen
++; /* returned value doesn't include room for '\0' */
2864 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2865 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2867 dlen
= datalen
* sizeof(WCHAR
);
2870 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2871 &dlen
) == ERROR_SUCCESS
) {
2873 RegDeleteValueW(winnt_key
, valueW
);
2874 RegDeleteValueW(win9x_key
, valueW
);
2875 /* reset dlen and vlen */
2879 HeapFree(GetProcessHeap(), 0, data
);
2880 HeapFree(GetProcessHeap(), 0, valueW
);
2882 /* Delete the old external fonts key */
2883 RegCloseKey(external_key
);
2884 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2887 if(win9x_key
) RegCloseKey(win9x_key
);
2888 if(winnt_key
) RegCloseKey(winnt_key
);
2891 /*************************************************************
2892 * WineEngAddFontResourceEx
2895 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2901 if (ft_handle
) /* do it only if we have freetype up and running */
2905 EnterCriticalSection( &freetype_cs
);
2907 if((unixname
= wine_get_unix_file_name(file
)))
2909 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2911 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2912 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2913 HeapFree(GetProcessHeap(), 0, unixname
);
2915 if (!ret
&& !strchrW(file
, '\\')) {
2916 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2917 if ((unixname
= get_winfonts_dir_path( file
)))
2919 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2920 HeapFree(GetProcessHeap(), 0, unixname
);
2922 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2923 if (!ret
&& (unixname
= get_data_dir_path( file
)))
2925 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2926 HeapFree(GetProcessHeap(), 0, unixname
);
2930 LeaveCriticalSection( &freetype_cs
);
2935 /*************************************************************
2936 * WineEngAddFontMemResourceEx
2939 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2943 if (ft_handle
) /* do it only if we have freetype up and running */
2945 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2947 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2948 memcpy(pFontCopy
, pbFont
, cbFont
);
2950 EnterCriticalSection( &freetype_cs
);
2951 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2952 LeaveCriticalSection( &freetype_cs
);
2956 TRACE("AddFontToList failed\n");
2957 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2960 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2961 * For now return something unique but quite random
2963 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2964 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2971 /*************************************************************
2972 * WineEngRemoveFontResourceEx
2975 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2981 if (ft_handle
) /* do it only if we have freetype up and running */
2985 EnterCriticalSection( &freetype_cs
);
2987 if ((unixname
= wine_get_unix_file_name(file
)))
2989 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2991 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2992 ret
= remove_font_resource( unixname
, addfont_flags
);
2993 HeapFree(GetProcessHeap(), 0, unixname
);
2995 if (!ret
&& !strchrW(file
, '\\'))
2997 if ((unixname
= get_winfonts_dir_path( file
)))
2999 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3000 HeapFree(GetProcessHeap(), 0, unixname
);
3002 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3004 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3005 HeapFree(GetProcessHeap(), 0, unixname
);
3009 LeaveCriticalSection( &freetype_cs
);
3014 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3020 if (!font_file
) return NULL
;
3022 file_len
= strlenW( font_file
);
3024 if (font_path
&& font_path
[0])
3026 int path_len
= strlenW( font_path
);
3027 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3028 if (!fullname
) return NULL
;
3029 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3030 fullname
[path_len
] = '\\';
3031 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3035 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3036 if (!len
) return NULL
;
3037 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3038 if (!fullname
) return NULL
;
3039 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3042 unix_name
= wine_get_unix_file_name( fullname
);
3043 HeapFree( GetProcessHeap(), 0, fullname
);
3047 #include <pshpack1.h>
3050 WORD num_of_resources
;
3054 CHAR dfCopyright
[60];
3060 WORD dfInternalLeading
;
3061 WORD dfExternalLeading
;
3069 BYTE dfPitchAndFamily
;
3080 CHAR szFaceName
[LF_FACESIZE
];
3083 #include <poppack.h>
3085 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3086 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3088 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3090 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3092 WCHAR
*name
, *english_name
;
3094 NEWTEXTMETRICEXW ntm
;
3097 if (!ft_face
) return FALSE
;
3098 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3099 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3100 pFT_Done_Face( ft_face
);
3102 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3103 release_face( face
);
3104 HeapFree( GetProcessHeap(), 0, name
);
3105 HeapFree( GetProcessHeap(), 0, english_name
);
3107 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3109 memset( fd
, 0, sizeof(*fd
) );
3111 fd
->num_of_resources
= 1;
3113 fd
->dfVersion
= 0x200;
3114 fd
->dfSize
= sizeof(*fd
);
3115 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3116 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3117 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3119 fd
->dfHorizRes
= 72;
3120 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3121 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3122 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3123 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3124 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3125 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3126 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3127 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3129 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3130 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3131 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3132 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3133 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3134 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3135 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3136 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3137 fd
->dfWidthBytes
= 0;
3139 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3141 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3146 #define NE_FFLAGS_LIBMODULE 0x8000
3147 #define NE_OSFLAGS_WINDOWS 0x02
3149 static const char dos_string
[0x40] = "This is a TrueType resource file";
3150 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3152 #include <pshpack2.h>
3173 struct ne_typeinfo fontdir_type
;
3174 struct ne_nameinfo fontdir_name
;
3175 struct ne_typeinfo scalable_type
;
3176 struct ne_nameinfo scalable_name
;
3178 BYTE fontdir_res_name
[8];
3181 #include <poppack.h>
3183 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3187 DWORD size
, written
;
3189 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3190 char *font_fileA
, *last_part
, *ext
;
3191 IMAGE_DOS_HEADER dos
;
3192 IMAGE_OS2_HEADER ne
=
3194 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3196 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3197 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3199 struct rsrc_tab rsrc_tab
=
3203 { 0, 0, 0x0c50, 0x2c, 0 },
3205 { 0, 0, 0x0c50, 0x8001, 0 },
3207 { 7,'F','O','N','T','D','I','R'}
3210 memset( &dos
, 0, sizeof(dos
) );
3211 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3212 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3214 /* import name is last part\0, resident name is last part without extension
3215 non-resident name is "FONTRES:" + lfFaceName */
3217 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3218 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3219 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3221 last_part
= strrchr( font_fileA
, '\\' );
3222 if (last_part
) last_part
++;
3223 else last_part
= font_fileA
;
3224 import_name_len
= strlen( last_part
) + 1;
3226 ext
= strchr( last_part
, '.' );
3227 if (ext
) res_name_len
= ext
- last_part
;
3228 else res_name_len
= import_name_len
- 1;
3230 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3232 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3233 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3234 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3235 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3237 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3239 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3240 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3241 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3242 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3244 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3245 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3249 HeapFree( GetProcessHeap(), 0, font_fileA
);
3253 memcpy( ptr
, &dos
, sizeof(dos
) );
3254 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3255 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3257 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3258 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3260 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3261 *ptr
++ = res_name_len
;
3262 memcpy( ptr
, last_part
, res_name_len
);
3264 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3265 *ptr
++ = import_name_len
;
3266 memcpy( ptr
, last_part
, import_name_len
);
3268 ptr
= start
+ ne
.ne_nrestab
;
3269 *ptr
++ = non_res_name_len
;
3270 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3271 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3273 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3274 memcpy( ptr
, font_fileA
, font_file_len
);
3276 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3277 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3279 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3280 if (file
!= INVALID_HANDLE_VALUE
)
3282 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3284 CloseHandle( file
);
3287 HeapFree( GetProcessHeap(), 0, start
);
3288 HeapFree( GetProcessHeap(), 0, font_fileA
);
3293 /*************************************************************
3294 * WineEngCreateScalableFontResource
3297 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3298 LPCWSTR font_file
, LPCWSTR font_path
)
3300 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3301 struct fontdir fontdir
;
3304 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3305 SetLastError( ERROR_INVALID_PARAMETER
);
3308 if (hidden
) fontdir
.dfType
|= 0x80;
3309 ret
= create_fot( resource
, font_file
, &fontdir
);
3312 HeapFree( GetProcessHeap(), 0, unix_name
);
3316 static const struct nls_update_font_list
3318 UINT ansi_cp
, oem_cp
;
3319 const char *oem
, *fixed
, *system
;
3320 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3321 /* these are for font substitutes */
3322 const char *shelldlg
, *tmsrmn
;
3323 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3327 const char *from
, *to
;
3328 } arial_0
, courier_new_0
, times_new_roman_0
;
3329 } nls_update_font_list
[] =
3331 /* Latin 1 (United States) */
3332 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3333 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3334 "Tahoma","Times New Roman",
3335 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3338 /* Latin 1 (Multilingual) */
3339 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3340 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3341 "Tahoma","Times New Roman", /* FIXME unverified */
3342 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3345 /* Eastern Europe */
3346 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3347 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3348 "Tahoma","Times New Roman", /* FIXME unverified */
3349 "Fixedsys,238", "System,238",
3350 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3351 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3352 { "Arial CE,0", "Arial,238" },
3353 { "Courier New CE,0", "Courier New,238" },
3354 { "Times New Roman CE,0", "Times New Roman,238" }
3357 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3358 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3359 "Tahoma","Times New Roman", /* FIXME unverified */
3360 "Fixedsys,204", "System,204",
3361 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3362 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3363 { "Arial Cyr,0", "Arial,204" },
3364 { "Courier New Cyr,0", "Courier New,204" },
3365 { "Times New Roman Cyr,0", "Times New Roman,204" }
3368 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3369 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3370 "Tahoma","Times New Roman", /* FIXME unverified */
3371 "Fixedsys,161", "System,161",
3372 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3373 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3374 { "Arial Greek,0", "Arial,161" },
3375 { "Courier New Greek,0", "Courier New,161" },
3376 { "Times New Roman Greek,0", "Times New Roman,161" }
3379 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3380 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3381 "Tahoma","Times New Roman", /* FIXME unverified */
3382 "Fixedsys,162", "System,162",
3383 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3384 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3385 { "Arial Tur,0", "Arial,162" },
3386 { "Courier New Tur,0", "Courier New,162" },
3387 { "Times New Roman Tur,0", "Times New Roman,162" }
3390 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3391 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3392 "Tahoma","Times New Roman", /* FIXME unverified */
3393 "Fixedsys,177", "System,177",
3394 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3395 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3399 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3400 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3401 "Tahoma","Times New Roman", /* FIXME unverified */
3402 "Fixedsys,178", "System,178",
3403 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3404 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3408 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3409 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3410 "Tahoma","Times New Roman", /* FIXME unverified */
3411 "Fixedsys,186", "System,186",
3412 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3413 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3414 { "Arial Baltic,0", "Arial,186" },
3415 { "Courier New Baltic,0", "Courier New,186" },
3416 { "Times New Roman Baltic,0", "Times New Roman,186" }
3419 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3420 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3421 "Tahoma","Times New Roman", /* FIXME unverified */
3422 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3426 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3427 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3428 "Tahoma","Times New Roman", /* FIXME unverified */
3429 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3433 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3434 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3435 "MS UI Gothic","MS Serif",
3436 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3439 /* Chinese Simplified */
3440 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3441 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3442 "SimSun", "NSimSun",
3443 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3447 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3450 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3453 /* Chinese Traditional */
3454 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3455 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3456 "PMingLiU", "MingLiU",
3457 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3462 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3464 return ( ansi_cp
== 932 /* CP932 for Japanese */
3465 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3466 || ansi_cp
== 949 /* CP949 for Korean */
3467 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3470 static inline HKEY
create_fonts_NT_registry_key(void)
3474 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3475 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3479 static inline HKEY
create_fonts_9x_registry_key(void)
3483 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3484 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3488 static inline HKEY
create_config_fonts_registry_key(void)
3492 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3493 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3497 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3499 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3501 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3502 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3503 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3504 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3507 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3510 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3512 RegDeleteValueA(hkey
, name
);
3515 static void update_font_association_info(UINT current_ansi_codepage
)
3517 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3518 static const char *assoc_charset_subkey
= "Associated Charset";
3520 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3523 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3526 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3528 switch (current_ansi_codepage
)
3531 set_value_key(hsubkey
, "ANSI(00)", "NO");
3532 set_value_key(hsubkey
, "OEM(FF)", "NO");
3533 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3538 set_value_key(hsubkey
, "ANSI(00)", "YES");
3539 set_value_key(hsubkey
, "OEM(FF)", "YES");
3540 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3543 RegCloseKey(hsubkey
);
3546 /* TODO: Associated DefaultFonts */
3552 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3555 static void update_font_info(void)
3557 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3558 char buf
[40], cpbuf
[40];
3561 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3562 DWORD screen_dpi
= 96, font_dpi
= 0;
3565 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3566 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3567 &hkey
) == ERROR_SUCCESS
)
3569 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3573 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3576 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3578 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3579 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3580 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3581 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3582 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3584 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3585 if (is_dbcs_ansi_cp(ansi_cp
))
3586 use_default_fallback
= TRUE
;
3590 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3592 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3597 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3598 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3600 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3601 ansi_cp
, oem_cp
, screen_dpi
);
3603 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3604 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3607 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3611 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3612 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3614 hkey
= create_config_fonts_registry_key();
3615 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3616 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3617 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3620 hkey
= create_fonts_NT_registry_key();
3621 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3624 hkey
= create_fonts_9x_registry_key();
3625 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3628 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3630 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3631 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3632 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3633 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3635 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3636 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3637 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3638 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3639 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3640 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3641 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3642 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3644 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3645 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3646 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3654 /* Delete the FontSubstitutes from other locales */
3655 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3657 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3658 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3659 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3665 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3667 /* update locale dependent font association info in registry.
3668 update only when codepages changed, not logpixels. */
3669 if (strcmp(buf
, cpbuf
) != 0)
3670 update_font_association_info(ansi_cp
);
3673 static BOOL
init_freetype(void)
3675 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3678 "Wine cannot find the FreeType font library. To enable Wine to\n"
3679 "use TrueType fonts please install a version of FreeType greater than\n"
3680 "or equal to 2.0.5.\n"
3681 "http://www.freetype.org\n");
3685 #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;}
3687 LOAD_FUNCPTR(FT_Done_Face
)
3688 LOAD_FUNCPTR(FT_Get_Char_Index
)
3689 LOAD_FUNCPTR(FT_Get_First_Char
)
3690 LOAD_FUNCPTR(FT_Get_Module
)
3691 LOAD_FUNCPTR(FT_Get_Next_Char
)
3692 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3693 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3694 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3695 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3696 LOAD_FUNCPTR(FT_Init_FreeType
)
3697 LOAD_FUNCPTR(FT_Library_Version
)
3698 LOAD_FUNCPTR(FT_Load_Glyph
)
3699 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3700 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3701 #ifndef FT_MULFIX_INLINED
3702 LOAD_FUNCPTR(FT_MulFix
)
3704 LOAD_FUNCPTR(FT_New_Face
)
3705 LOAD_FUNCPTR(FT_New_Memory_Face
)
3706 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3707 LOAD_FUNCPTR(FT_Outline_Transform
)
3708 LOAD_FUNCPTR(FT_Outline_Translate
)
3709 LOAD_FUNCPTR(FT_Render_Glyph
)
3710 LOAD_FUNCPTR(FT_Select_Charmap
)
3711 LOAD_FUNCPTR(FT_Set_Charmap
)
3712 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3713 LOAD_FUNCPTR(FT_Vector_Transform
)
3714 LOAD_FUNCPTR(FT_Vector_Unit
)
3716 /* Don't warn if these ones are missing */
3717 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3718 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3719 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3722 if(pFT_Init_FreeType(&library
) != 0) {
3723 ERR("Can't init FreeType library\n");
3724 wine_dlclose(ft_handle
, NULL
, 0);
3728 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3730 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3731 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3732 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3733 ((FT_Version
.patch
) & 0x0000ff);
3735 font_driver
= &freetype_funcs
;
3740 "Wine cannot find certain functions that it needs inside the FreeType\n"
3741 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3742 "FreeType to at least version 2.1.4.\n"
3743 "http://www.freetype.org\n");
3744 wine_dlclose(ft_handle
, NULL
, 0);
3749 static void init_font_list(void)
3751 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3752 static const WCHAR pathW
[] = {'P','a','t','h',0};
3754 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3755 WCHAR windowsdir
[MAX_PATH
];
3757 const char *data_dir
;
3759 delete_external_font_keys();
3761 /* load the system bitmap fonts */
3762 load_system_fonts();
3764 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3765 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3766 strcatW(windowsdir
, fontsW
);
3767 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3769 ReadFontDir(unixname
, FALSE
);
3770 HeapFree(GetProcessHeap(), 0, unixname
);
3773 /* load the system truetype fonts */
3774 data_dir
= wine_get_data_dir();
3775 if (!data_dir
) data_dir
= wine_get_build_dir();
3776 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3778 strcpy(unixname
, data_dir
);
3779 strcat(unixname
, "/fonts/");
3780 ReadFontDir(unixname
, TRUE
);
3781 HeapFree(GetProcessHeap(), 0, unixname
);
3784 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3785 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3786 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3788 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3789 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3790 &hkey
) == ERROR_SUCCESS
)
3792 LPWSTR data
, valueW
;
3793 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3794 &valuelen
, &datalen
, NULL
, NULL
);
3796 valuelen
++; /* returned value doesn't include room for '\0' */
3797 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3798 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3801 dlen
= datalen
* sizeof(WCHAR
);
3803 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3804 &dlen
) == ERROR_SUCCESS
)
3806 if(data
[0] && (data
[1] == ':'))
3808 if((unixname
= wine_get_unix_file_name(data
)))
3810 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3811 HeapFree(GetProcessHeap(), 0, unixname
);
3814 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3816 WCHAR pathW
[MAX_PATH
];
3817 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3820 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3821 if((unixname
= wine_get_unix_file_name(pathW
)))
3823 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3824 HeapFree(GetProcessHeap(), 0, unixname
);
3827 load_font_from_data_dir(data
);
3829 /* reset dlen and vlen */
3834 HeapFree(GetProcessHeap(), 0, data
);
3835 HeapFree(GetProcessHeap(), 0, valueW
);
3839 #ifdef SONAME_LIBFONTCONFIG
3840 load_fontconfig_fonts();
3841 #elif defined(HAVE_CARBON_CARBON_H)
3845 /* then look in any directories that we've specified in the config file */
3846 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3847 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3853 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3855 len
+= sizeof(WCHAR
);
3856 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3857 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3859 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3860 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3861 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3862 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3867 LPSTR next
= strchr( ptr
, ':' );
3868 if (next
) *next
++ = 0;
3869 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3870 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3872 strcpy( unixname
, home
);
3873 strcat( unixname
, ptr
+ 1 );
3874 ReadFontDir( unixname
, TRUE
);
3875 HeapFree( GetProcessHeap(), 0, unixname
);
3878 ReadFontDir( ptr
, TRUE
);
3881 HeapFree( GetProcessHeap(), 0, valueA
);
3883 HeapFree( GetProcessHeap(), 0, valueW
);
3889 static BOOL
move_to_front(const WCHAR
*name
)
3891 Family
*family
, *cursor2
;
3892 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3894 if(!strcmpiW(family
->FamilyName
, name
))
3896 list_remove(&family
->entry
);
3897 list_add_head(&font_list
, &family
->entry
);
3904 static BOOL
set_default(const WCHAR
**name_list
)
3908 if (move_to_front(*name_list
)) return TRUE
;
3915 static void reorder_font_list(void)
3917 set_default( default_serif_list
);
3918 set_default( default_fixed_list
);
3919 set_default( default_sans_list
);
3922 /*************************************************************
3925 * Initialize FreeType library and create a list of available faces
3927 BOOL
WineEngInit(void)
3932 /* update locale dependent font info in registry */
3935 if(!init_freetype()) return FALSE
;
3937 #ifdef SONAME_LIBFONTCONFIG
3941 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3943 ERR("Failed to create font mutex\n");
3946 WaitForSingleObject(font_mutex
, INFINITE
);
3948 create_font_cache_key(&hkey_font_cache
, &disposition
);
3950 if(disposition
== REG_CREATED_NEW_KEY
)
3953 load_font_list_from_cache(hkey_font_cache
);
3955 reorder_font_list();
3962 if(disposition
== REG_CREATED_NEW_KEY
)
3963 update_reg_entries();
3965 init_system_links();
3967 ReleaseMutex(font_mutex
);
3972 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3975 TT_HoriHeader
*pHori
;
3979 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3980 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3982 if(height
== 0) height
= 16;
3984 /* Calc. height of EM square:
3986 * For +ve lfHeight we have
3987 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3988 * Re-arranging gives:
3989 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3991 * For -ve lfHeight we have
3993 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3994 * with il = winAscent + winDescent - units_per_em]
3999 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
4000 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4001 pHori
->Ascender
- pHori
->Descender
);
4003 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4004 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
4012 static struct font_mapping
*map_font_file( const char *name
)
4014 struct font_mapping
*mapping
;
4018 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4019 if (fstat( fd
, &st
) == -1) goto error
;
4021 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4023 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4025 mapping
->refcount
++;
4030 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4033 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4036 if (mapping
->data
== MAP_FAILED
)
4038 HeapFree( GetProcessHeap(), 0, mapping
);
4041 mapping
->refcount
= 1;
4042 mapping
->dev
= st
.st_dev
;
4043 mapping
->ino
= st
.st_ino
;
4044 mapping
->size
= st
.st_size
;
4045 list_add_tail( &mappings_list
, &mapping
->entry
);
4053 static void unmap_font_file( struct font_mapping
*mapping
)
4055 if (!--mapping
->refcount
)
4057 list_remove( &mapping
->entry
);
4058 munmap( mapping
->data
, mapping
->size
);
4059 HeapFree( GetProcessHeap(), 0, mapping
);
4063 static LONG
load_VDMX(GdiFont
*, LONG
);
4065 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4072 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4076 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4077 font
->mapping
= map_font_file( filename
);
4078 HeapFree( GetProcessHeap(), 0, filename
);
4081 WARN("failed to map %s\n", debugstr_w(face
->file
));
4084 data_ptr
= font
->mapping
->data
;
4085 data_size
= font
->mapping
->size
;
4089 data_ptr
= face
->font_data_ptr
;
4090 data_size
= face
->font_data_size
;
4093 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4095 ERR("FT_New_Face rets %d\n", err
);
4099 /* set it here, as load_VDMX needs it */
4100 font
->ft_face
= ft_face
;
4102 if(FT_IS_SCALABLE(ft_face
)) {
4103 /* load the VDMX table if we have one */
4104 font
->ppem
= load_VDMX(font
, height
);
4106 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4107 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4109 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4110 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4112 font
->ppem
= height
;
4113 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4114 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4120 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4122 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4123 a single face with the requested charset. The idea is to check if
4124 the selected font supports the current ANSI codepage, if it does
4125 return the corresponding charset, else return the first charset */
4128 int acp
= GetACP(), i
;
4132 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4134 const SYSTEM_LINKS
*font_link
;
4136 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4137 return csi
.ciCharset
;
4139 font_link
= find_font_link(family_name
);
4140 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4141 return csi
.ciCharset
;
4144 for(i
= 0; i
< 32; i
++) {
4146 if(face
->fs
.fsCsb
[0] & fs0
) {
4147 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4149 return csi
.ciCharset
;
4152 FIXME("TCI failing on %x\n", fs0
);
4156 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4157 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4159 return DEFAULT_CHARSET
;
4162 static GdiFont
*alloc_font(void)
4164 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4167 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4168 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4170 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4171 ret
->total_kern_pairs
= (DWORD
)-1;
4172 ret
->kern_pairs
= NULL
;
4173 list_init(&ret
->child_fonts
);
4177 static void free_font(GdiFont
*font
)
4179 CHILD_FONT
*child
, *child_next
;
4182 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4184 list_remove(&child
->entry
);
4186 free_font(child
->font
);
4187 release_face( child
->face
);
4188 HeapFree(GetProcessHeap(), 0, child
);
4191 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4192 if (font
->mapping
) unmap_font_file( font
->mapping
);
4193 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4194 HeapFree(GetProcessHeap(), 0, font
->potm
);
4195 HeapFree(GetProcessHeap(), 0, font
->name
);
4196 for (i
= 0; i
< font
->gmsize
; i
++)
4197 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4198 HeapFree(GetProcessHeap(), 0, font
->gm
);
4199 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4200 HeapFree(GetProcessHeap(), 0, font
);
4204 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4206 FT_Face ft_face
= font
->ft_face
;
4210 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4217 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4219 /* make sure value of len is the value freetype says it needs */
4222 FT_ULong needed
= 0;
4223 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4224 if( !err
&& needed
< len
) len
= needed
;
4226 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4229 TRACE("Can't find table %c%c%c%c\n",
4230 /* bytes were reversed */
4231 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4232 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4238 /*************************************************************
4241 * load the vdmx entry for the specified height
4244 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4245 ( ( (FT_ULong)_x4 << 24 ) | \
4246 ( (FT_ULong)_x3 << 16 ) | \
4247 ( (FT_ULong)_x2 << 8 ) | \
4250 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4265 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4269 BYTE devXRatio
, devYRatio
;
4270 USHORT numRecs
, numRatios
;
4271 DWORD result
, offset
= -1;
4275 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4277 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4280 /* FIXME: need the real device aspect ratio */
4284 numRecs
= GET_BE_WORD(hdr
[1]);
4285 numRatios
= GET_BE_WORD(hdr
[2]);
4287 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4288 for(i
= 0; i
< numRatios
; i
++) {
4291 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4292 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4295 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4297 if((ratio
.xRatio
== 0 &&
4298 ratio
.yStartRatio
== 0 &&
4299 ratio
.yEndRatio
== 0) ||
4300 (devXRatio
== ratio
.xRatio
&&
4301 devYRatio
>= ratio
.yStartRatio
&&
4302 devYRatio
<= ratio
.yEndRatio
))
4304 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4305 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4306 offset
= GET_BE_WORD(tmp
);
4312 FIXME("No suitable ratio found\n");
4316 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4318 BYTE startsz
, endsz
;
4321 recs
= GET_BE_WORD(group
.recs
);
4322 startsz
= group
.startsz
;
4323 endsz
= group
.endsz
;
4325 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4327 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4328 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4329 if(result
== GDI_ERROR
) {
4330 FIXME("Failed to retrieve vTable\n");
4335 for(i
= 0; i
< recs
; i
++) {
4336 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4337 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4338 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4340 if(yMax
+ -yMin
== height
) {
4343 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4346 if(yMax
+ -yMin
> height
) {
4349 goto end
; /* failed */
4351 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4352 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4353 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4354 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4360 TRACE("ppem not found for height %d\n", height
);
4364 HeapFree(GetProcessHeap(), 0, vTable
);
4370 static void dump_gdi_font_list(void)
4374 TRACE("---------- Font Cache ----------\n");
4375 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4376 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4377 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4380 static void grab_font( GdiFont
*font
)
4382 if (!font
->refcount
++)
4384 list_remove( &font
->unused_entry
);
4385 unused_font_count
--;
4389 static void release_font( GdiFont
*font
)
4392 if (!--font
->refcount
)
4394 TRACE( "font %p\n", font
);
4396 /* add it to the unused list */
4397 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4398 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4400 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4401 TRACE( "freeing %p\n", font
);
4402 list_remove( &font
->entry
);
4403 list_remove( &font
->unused_entry
);
4406 else unused_font_count
++;
4408 if (TRACE_ON(font
)) dump_gdi_font_list();
4412 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4414 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4415 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4416 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4417 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4418 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4421 static void calc_hash(FONT_DESC
*pfd
)
4423 DWORD hash
= 0, *ptr
, two_chars
;
4427 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4429 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4431 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4433 pwc
= (WCHAR
*)&two_chars
;
4435 *pwc
= toupperW(*pwc
);
4437 *pwc
= toupperW(*pwc
);
4441 hash
^= !pfd
->can_use_bitmap
;
4446 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4453 fd
.can_use_bitmap
= can_use_bitmap
;
4456 /* try the in-use list */
4457 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4459 if(fontcmp(ret
, &fd
)) continue;
4460 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4461 list_remove( &ret
->entry
);
4462 list_add_head( &gdi_font_list
, &ret
->entry
);
4469 static void add_to_cache(GdiFont
*font
)
4471 static DWORD cache_num
= 1;
4473 font
->cache_num
= cache_num
++;
4474 list_add_head(&gdi_font_list
, &font
->entry
);
4475 TRACE( "font %p\n", font
);
4478 /*************************************************************
4479 * create_child_font_list
4481 static BOOL
create_child_font_list(GdiFont
*font
)
4484 SYSTEM_LINKS
*font_link
;
4485 CHILD_FONT
*font_link_entry
, *new_child
;
4489 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4490 font_name
= psub
? psub
->to
.name
: font
->name
;
4491 font_link
= find_font_link(font_name
);
4492 if (font_link
!= NULL
)
4494 TRACE("found entry in system list\n");
4495 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4497 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4498 new_child
->face
= font_link_entry
->face
;
4499 new_child
->font
= NULL
;
4500 new_child
->face
->refcount
++;
4501 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4502 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4507 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4508 * Sans Serif. This is how asian windows get default fallbacks for fonts
4510 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4511 font
->charset
!= OEM_CHARSET
&&
4512 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4514 font_link
= find_font_link(szDefaultFallbackLink
);
4515 if (font_link
!= NULL
)
4517 TRACE("found entry in default fallback list\n");
4518 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4520 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4521 new_child
->face
= font_link_entry
->face
;
4522 new_child
->font
= NULL
;
4523 new_child
->face
->refcount
++;
4524 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4525 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4534 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4536 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4538 if (pFT_Set_Charmap
)
4541 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4543 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4545 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4547 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4549 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4550 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4552 switch (ft_face
->charmaps
[i
]->platform_id
)
4555 cmap_def
= ft_face
->charmaps
[i
];
4557 case 0: /* Apple Unicode */
4558 cmap0
= ft_face
->charmaps
[i
];
4560 case 1: /* Macintosh */
4561 cmap1
= ft_face
->charmaps
[i
];
4564 cmap2
= ft_face
->charmaps
[i
];
4566 case 3: /* Microsoft */
4567 cmap3
= ft_face
->charmaps
[i
];
4572 if (cmap3
) /* prefer Microsoft cmap table */
4573 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4575 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4577 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4579 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4581 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4583 return ft_err
== FT_Err_Ok
;
4586 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4590 /*************************************************************
4593 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4594 LPCWSTR output
, const DEVMODEW
*devmode
)
4596 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4598 if (!physdev
) return FALSE
;
4599 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4604 /*************************************************************
4607 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4609 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4610 release_font( physdev
->font
);
4611 HeapFree( GetProcessHeap(), 0, physdev
);
4615 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4617 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4618 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4619 const FT_Encoding
*encs
= regular_order
;
4621 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4625 if (select_charmap( face
, *encs
)) break;
4631 #define GASP_GRIDFIT 0x01
4632 #define GASP_DOGRAY 0x02
4633 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4635 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4638 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4639 WORD
*alloced
= NULL
, *ptr
= buf
;
4640 WORD num_recs
, version
;
4644 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4645 if (size
== GDI_ERROR
) return FALSE
;
4646 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4647 if (size
> sizeof(buf
))
4649 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4650 if (!ptr
) return FALSE
;
4653 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4655 version
= GET_BE_WORD( *ptr
++ );
4656 num_recs
= GET_BE_WORD( *ptr
++ );
4658 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4660 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4666 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4667 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4670 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4674 HeapFree( GetProcessHeap(), 0, alloced
);
4678 /*************************************************************
4679 * freetype_SelectFont
4681 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4683 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4685 Face
*face
, *best
, *best_bitmap
;
4686 Family
*family
, *last_resort_family
;
4687 const struct list
*face_list
;
4688 INT height
, width
= 0;
4689 unsigned int score
= 0, new_score
;
4690 signed int diff
= 0, newdiff
;
4691 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4695 FontSubst
*psub
= NULL
;
4696 DC
*dc
= get_dc_ptr( dev
->hdc
);
4697 const SYSTEM_LINKS
*font_link
;
4699 if (!hfont
) /* notification that the font has been changed by another driver */
4701 release_font( physdev
->font
);
4702 physdev
->font
= NULL
;
4703 release_dc_ptr( dc
);
4707 GetObjectW( hfont
, sizeof(lf
), &lf
);
4708 lf
.lfWidth
= abs(lf
.lfWidth
);
4710 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4712 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4713 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4714 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4717 if(dc
->GraphicsMode
== GM_ADVANCED
)
4719 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4720 /* Try to avoid not necessary glyph transformations */
4721 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4723 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4724 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4725 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4730 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4731 font scaling abilities. */
4732 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4733 dcmat
.eM21
= dcmat
.eM12
= 0;
4734 lf
.lfOrientation
= lf
.lfEscapement
;
4735 if (dc
->vport2WorldValid
)
4737 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4738 lf
.lfOrientation
= -lf
.lfOrientation
;
4739 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4740 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4744 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4745 dcmat
.eM21
, dcmat
.eM22
);
4748 EnterCriticalSection( &freetype_cs
);
4750 /* check the cache first */
4751 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4752 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4756 TRACE("not in cache\n");
4759 ret
->font_desc
.matrix
= dcmat
;
4760 ret
->font_desc
.lf
= lf
;
4761 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4762 calc_hash(&ret
->font_desc
);
4764 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4765 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4766 original value lfCharSet. Note this is a special case for
4767 Symbol and doesn't happen at least for "Wingdings*" */
4769 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4770 lf
.lfCharSet
= SYMBOL_CHARSET
;
4772 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4773 switch(lf
.lfCharSet
) {
4774 case DEFAULT_CHARSET
:
4775 csi
.fs
.fsCsb
[0] = 0;
4778 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4779 csi
.fs
.fsCsb
[0] = 0;
4785 if(lf
.lfFaceName
[0] != '\0') {
4786 CHILD_FONT
*font_link_entry
;
4787 LPWSTR FaceName
= lf
.lfFaceName
;
4789 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4792 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4793 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4794 if (psub
->to
.charset
!= -1)
4795 lf
.lfCharSet
= psub
->to
.charset
;
4798 /* We want a match on name and charset or just name if
4799 charset was DEFAULT_CHARSET. If the latter then
4800 we fixup the returned charset later in get_nearest_charset
4801 where we'll either use the charset of the current ansi codepage
4802 or if that's unavailable the first charset that the font supports.
4804 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4805 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4806 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4808 font_link
= find_font_link(family
->FamilyName
);
4809 face_list
= get_face_list_from_family(family
);
4810 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4811 if (!(face
->scalable
|| can_use_bitmap
))
4813 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4815 if (font_link
!= NULL
&&
4816 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4818 if (!csi
.fs
.fsCsb
[0])
4824 /* Search by full face name. */
4825 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4826 face_list
= get_face_list_from_family(family
);
4827 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4828 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4829 (face
->scalable
|| can_use_bitmap
))
4831 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4833 font_link
= find_font_link(family
->FamilyName
);
4834 if (font_link
!= NULL
&&
4835 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4842 * Try check the SystemLink list first for a replacement font.
4843 * We may find good replacements there.
4845 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4847 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4848 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4850 TRACE("found entry in system list\n");
4851 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4853 const SYSTEM_LINKS
*links
;
4855 face
= font_link_entry
->face
;
4856 if (!(face
->scalable
|| can_use_bitmap
))
4858 family
= face
->family
;
4859 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4861 links
= find_font_link(family
->FamilyName
);
4862 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4869 psub
= NULL
; /* substitution is no more relevant */
4871 /* If requested charset was DEFAULT_CHARSET then try using charset
4872 corresponding to the current ansi codepage */
4873 if (!csi
.fs
.fsCsb
[0])
4876 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4877 FIXME("TCI failed on codepage %d\n", acp
);
4878 csi
.fs
.fsCsb
[0] = 0;
4880 lf
.lfCharSet
= csi
.ciCharset
;
4883 want_vertical
= (lf
.lfFaceName
[0] == '@');
4885 /* Face families are in the top 4 bits of lfPitchAndFamily,
4886 so mask with 0xF0 before testing */
4888 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4889 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4890 strcpyW(lf
.lfFaceName
, defFixed
);
4891 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4892 strcpyW(lf
.lfFaceName
, defSerif
);
4893 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4894 strcpyW(lf
.lfFaceName
, defSans
);
4896 strcpyW(lf
.lfFaceName
, defSans
);
4897 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4898 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4899 font_link
= find_font_link(family
->FamilyName
);
4900 face_list
= get_face_list_from_family(family
);
4901 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4902 if (!(face
->scalable
|| can_use_bitmap
))
4904 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4906 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4912 last_resort_family
= NULL
;
4913 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4914 font_link
= find_font_link(family
->FamilyName
);
4915 face_list
= get_face_list_from_family(family
);
4916 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4917 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
4918 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4919 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4922 if(can_use_bitmap
&& !last_resort_family
)
4923 last_resort_family
= family
;
4928 if(last_resort_family
) {
4929 family
= last_resort_family
;
4930 csi
.fs
.fsCsb
[0] = 0;
4934 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4935 face_list
= get_face_list_from_family(family
);
4936 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4937 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
4938 csi
.fs
.fsCsb
[0] = 0;
4939 WARN("just using first face for now\n");
4942 if(can_use_bitmap
&& !last_resort_family
)
4943 last_resort_family
= family
;
4946 if(!last_resort_family
) {
4947 FIXME("can't find a single appropriate font - bailing\n");
4953 WARN("could only find a bitmap font - this will probably look awful!\n");
4954 family
= last_resort_family
;
4955 csi
.fs
.fsCsb
[0] = 0;
4958 it
= lf
.lfItalic
? 1 : 0;
4959 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4961 height
= lf
.lfHeight
;
4963 face
= best
= best_bitmap
= NULL
;
4964 font_link
= find_font_link(family
->FamilyName
);
4965 face_list
= get_face_list_from_family(family
);
4966 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4968 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4969 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4974 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4975 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4976 new_score
= (italic
^ it
) + (bold
^ bd
);
4977 if(!best
|| new_score
<= score
)
4979 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4980 italic
, bold
, it
, bd
);
4983 if(best
->scalable
&& score
== 0) break;
4987 newdiff
= height
- (signed int)(best
->size
.height
);
4989 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4990 if(!best_bitmap
|| new_score
< score
||
4991 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
4993 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
4996 if(score
== 0 && diff
== 0) break;
5003 face
= best
->scalable
? best
: best_bitmap
;
5004 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5005 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5008 height
= lf
.lfHeight
;
5012 if(csi
.fs
.fsCsb
[0]) {
5013 ret
->charset
= lf
.lfCharSet
;
5014 ret
->codepage
= csi
.ciACP
;
5017 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5019 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5020 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5022 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5024 if(!face
->scalable
) {
5025 /* Windows uses integer scaling factors for bitmap fonts */
5026 INT scale
, scaled_height
;
5027 GdiFont
*cachedfont
;
5029 /* FIXME: rotation of bitmap fonts is ignored */
5030 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5032 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5033 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5034 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5035 /* As we changed the matrix, we need to search the cache for the font again,
5036 * otherwise we might explode the cache. */
5037 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5038 TRACE("Found cached font after non-scalable matrix rescale!\n");
5043 calc_hash(&ret
->font_desc
);
5045 if (height
!= 0) height
= diff
;
5046 height
+= face
->size
.height
;
5048 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5049 scaled_height
= scale
* face
->size
.height
;
5050 /* Only jump to the next height if the difference <= 25% original height */
5051 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5052 /* The jump between unscaled and doubled is delayed by 1 */
5053 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5054 ret
->scale_y
= scale
;
5056 width
= face
->size
.x_ppem
>> 6;
5057 height
= face
->size
.y_ppem
>> 6;
5061 TRACE("font scale y: %f\n", ret
->scale_y
);
5063 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5072 ret
->ntmFlags
= face
->ntmFlags
;
5074 pick_charmap( ret
->ft_face
, ret
->charset
);
5076 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5077 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5078 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5079 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5080 create_child_font_list(ret
);
5082 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5084 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5085 if (length
!= GDI_ERROR
)
5087 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5088 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5089 TRACE("Loaded GSUB table of %i bytes\n",length
);
5092 ret
->aa_flags
= HIWORD( face
->flags
);
5094 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5100 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5102 switch (lf
.lfQuality
)
5104 case NONANTIALIASED_QUALITY
:
5105 case ANTIALIASED_QUALITY
:
5106 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5108 case CLEARTYPE_QUALITY
:
5109 case CLEARTYPE_NATURAL_QUALITY
:
5111 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5112 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5114 /* fixup the antialiasing flags for that font */
5117 case WINE_GGO_HRGB_BITMAP
:
5118 case WINE_GGO_HBGR_BITMAP
:
5119 case WINE_GGO_VRGB_BITMAP
:
5120 case WINE_GGO_VBGR_BITMAP
:
5121 if (is_subpixel_rendering_enabled()) break;
5122 *aa_flags
= GGO_GRAY4_BITMAP
;
5124 case GGO_GRAY2_BITMAP
:
5125 case GGO_GRAY4_BITMAP
:
5126 case GGO_GRAY8_BITMAP
:
5127 case WINE_GGO_GRAY16_BITMAP
:
5128 if (is_hinting_enabled())
5131 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5133 TRACE( "font %s %d aa disabled by GASP\n",
5134 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5135 *aa_flags
= GGO_BITMAP
;
5140 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5141 release_font( physdev
->font
);
5142 physdev
->font
= ret
;
5144 LeaveCriticalSection( &freetype_cs
);
5145 release_dc_ptr( dc
);
5146 return ret
? hfont
: 0;
5149 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5156 id
+= IDS_FIRST_SCRIPT
;
5157 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5158 if (!rsrc
) return 0;
5159 hMem
= LoadResource( gdi32_module
, rsrc
);
5160 if (!hMem
) return 0;
5162 p
= LockResource( hMem
);
5164 while (id
--) p
+= *p
+ 1;
5166 i
= min(LF_FACESIZE
- 1, *p
);
5167 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5173 /***************************************************
5174 * create_enum_charset_list
5176 * This function creates charset enumeration list because in DEFAULT_CHARSET
5177 * case, the ANSI codepage's charset takes precedence over other charsets.
5178 * This function works as a filter other than DEFAULT_CHARSET case.
5180 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5185 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5186 csi
.fs
.fsCsb
[0] != 0) {
5187 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5188 list
->element
[n
].charset
= csi
.ciCharset
;
5189 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5192 else { /* charset is DEFAULT_CHARSET or invalid. */
5196 /* Set the current codepage's charset as the first element. */
5198 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5199 csi
.fs
.fsCsb
[0] != 0) {
5200 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5201 list
->element
[n
].charset
= csi
.ciCharset
;
5202 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5203 mask
|= csi
.fs
.fsCsb
[0];
5207 /* Fill out left elements. */
5208 for (i
= 0; i
< 32; i
++) {
5210 fs
.fsCsb
[0] = 1L << i
;
5212 if (fs
.fsCsb
[0] & mask
)
5213 continue; /* skip, already added. */
5214 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5215 continue; /* skip, this is an invalid fsCsb bit. */
5217 list
->element
[n
].mask
= fs
.fsCsb
[0];
5218 list
->element
[n
].charset
= csi
.ciCharset
;
5219 load_script_name( i
, list
->element
[n
].name
);
5220 mask
|= fs
.fsCsb
[0];
5224 /* add catch all mask for remaining bits */
5227 list
->element
[n
].mask
= ~mask
;
5228 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5229 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5238 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5239 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5244 if (face
->cached_enum_data
)
5247 *pelf
= face
->cached_enum_data
->elf
;
5248 *pntm
= face
->cached_enum_data
->ntm
;
5249 *ptype
= face
->cached_enum_data
->type
;
5253 font
= alloc_font();
5255 if(face
->scalable
) {
5259 height
= face
->size
.y_ppem
>> 6;
5260 width
= face
->size
.x_ppem
>> 6;
5262 font
->scale_y
= 1.0;
5264 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5270 font
->name
= strdupW( family_name
);
5271 font
->ntmFlags
= face
->ntmFlags
;
5273 if (get_outline_text_metrics(font
))
5275 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5277 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5278 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5279 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5281 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5282 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5284 lstrcpynW(pelf
->elfFullName
,
5285 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5287 lstrcpynW(pelf
->elfStyle
,
5288 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5293 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5295 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5296 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5297 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5299 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5301 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5303 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5304 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5307 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5308 pntm
->ntmFontSig
= face
->fs
;
5310 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5312 pelf
->elfLogFont
.lfEscapement
= 0;
5313 pelf
->elfLogFont
.lfOrientation
= 0;
5314 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5315 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5316 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5317 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5318 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5319 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5320 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5321 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5322 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5323 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5324 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5327 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5328 *ptype
|= TRUETYPE_FONTTYPE
;
5329 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5330 *ptype
|= DEVICE_FONTTYPE
;
5331 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5332 *ptype
|= RASTER_FONTTYPE
;
5334 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5335 if (face
->cached_enum_data
)
5337 face
->cached_enum_data
->elf
= *pelf
;
5338 face
->cached_enum_data
->ntm
= *pntm
;
5339 face
->cached_enum_data
->type
= *ptype
;
5345 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5348 const struct list
*face_list
;
5350 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5352 face_list
= get_face_list_from_family(family
);
5353 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5354 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5359 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5361 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5363 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5366 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5367 FONTENUMPROCW proc
, LPARAM lparam
)
5370 NEWTEXTMETRICEXW ntm
;
5374 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5375 for(i
= 0; i
< list
->total
; i
++) {
5376 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5377 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5378 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5379 i
= list
->total
; /* break out of loop after enumeration */
5383 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5384 /* use the DEFAULT_CHARSET case only if no other charset is present */
5385 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5386 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5387 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5388 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5389 if (!elf
.elfScript
[0])
5390 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5392 /* Font Replacement */
5393 if (family
!= face
->family
)
5395 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5397 strcpyW(elf
.elfFullName
, face
->FullName
);
5399 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5401 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5402 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5403 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5404 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5405 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5406 ntm
.ntmTm
.ntmFlags
);
5407 /* release section before callback (FIXME) */
5408 LeaveCriticalSection( &freetype_cs
);
5409 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5410 EnterCriticalSection( &freetype_cs
);
5415 /*************************************************************
5416 * freetype_EnumFonts
5418 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5422 const struct list
*face_list
;
5424 struct enum_charset_list enum_charsets
;
5428 lf
.lfCharSet
= DEFAULT_CHARSET
;
5429 lf
.lfPitchAndFamily
= 0;
5430 lf
.lfFaceName
[0] = 0;
5434 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5436 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5439 EnterCriticalSection( &freetype_cs
);
5440 if(plf
->lfFaceName
[0]) {
5442 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5445 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5446 debugstr_w(psub
->to
.name
));
5448 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5452 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5453 if (!family_matches(family
, plf
)) continue;
5454 face_list
= get_face_list_from_family(family
);
5455 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5456 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5457 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5461 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5462 face_list
= get_face_list_from_family(family
);
5463 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5464 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5467 LeaveCriticalSection( &freetype_cs
);
5471 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5473 pt
->x
.value
= vec
->x
>> 6;
5474 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5475 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5476 pt
->y
.value
= vec
->y
>> 6;
5477 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5478 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5482 /***************************************************
5483 * According to the MSDN documentation on WideCharToMultiByte,
5484 * certain codepages cannot set the default_used parameter.
5485 * This returns TRUE if the codepage can set that parameter, false else
5486 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5488 static BOOL
codepage_sets_default_used(UINT codepage
)
5502 * GSUB Table handling functions
5505 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5507 const GSUB_CoverageFormat1
* cf1
;
5511 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5513 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5515 TRACE("Coverage Format 1, %i glyphs\n",count
);
5516 for (i
= 0; i
< count
; i
++)
5517 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5521 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5523 const GSUB_CoverageFormat2
* cf2
;
5526 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5528 count
= GET_BE_WORD(cf2
->RangeCount
);
5529 TRACE("Coverage Format 2, %i ranges\n",count
);
5530 for (i
= 0; i
< count
; i
++)
5532 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5534 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5535 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5537 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5538 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5544 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5549 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5551 const GSUB_ScriptList
*script
;
5552 const GSUB_Script
*deflt
= NULL
;
5554 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5556 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5557 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5559 const GSUB_Script
*scr
;
5562 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5563 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5565 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5567 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5573 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5577 const GSUB_LangSys
*Lang
;
5579 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5581 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5583 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5584 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5586 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5589 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5592 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5598 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5601 const GSUB_FeatureList
*feature
;
5602 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5604 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5605 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5607 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5608 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5610 const GSUB_Feature
*feat
;
5611 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5618 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5622 const GSUB_LookupList
*lookup
;
5623 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5625 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5626 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5628 const GSUB_LookupTable
*look
;
5629 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5630 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5631 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5632 if (GET_BE_WORD(look
->LookupType
) != 1)
5633 FIXME("We only handle SubType 1\n");
5638 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5640 const GSUB_SingleSubstFormat1
*ssf1
;
5641 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5642 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5643 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5645 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5646 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5647 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5649 TRACE(" Glyph 0x%x ->",glyph
);
5650 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5651 TRACE(" 0x%x\n",glyph
);
5656 const GSUB_SingleSubstFormat2
*ssf2
;
5660 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5661 offset
= GET_BE_WORD(ssf1
->Coverage
);
5662 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5663 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5664 TRACE(" Coverage index %i\n",index
);
5667 TRACE(" Glyph is 0x%x ->",glyph
);
5668 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5669 TRACE("0x%x\n",glyph
);
5678 static const char* get_opentype_script(const GdiFont
*font
)
5681 * I am not sure if this is the correct way to generate our script tag
5684 switch (font
->charset
)
5686 case ANSI_CHARSET
: return "latn";
5687 case BALTIC_CHARSET
: return "latn"; /* ?? */
5688 case CHINESEBIG5_CHARSET
: return "hani";
5689 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5690 case GB2312_CHARSET
: return "hani";
5691 case GREEK_CHARSET
: return "grek";
5692 case HANGUL_CHARSET
: return "hang";
5693 case RUSSIAN_CHARSET
: return "cyrl";
5694 case SHIFTJIS_CHARSET
: return "kana";
5695 case TURKISH_CHARSET
: return "latn"; /* ?? */
5696 case VIETNAMESE_CHARSET
: return "latn";
5697 case JOHAB_CHARSET
: return "latn"; /* ?? */
5698 case ARABIC_CHARSET
: return "arab";
5699 case HEBREW_CHARSET
: return "hebr";
5700 case THAI_CHARSET
: return "thai";
5701 default: return "latn";
5705 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5707 const GSUB_Header
*header
;
5708 const GSUB_Script
*script
;
5709 const GSUB_LangSys
*language
;
5710 const GSUB_Feature
*feature
;
5712 if (!font
->GSUB_Table
)
5715 header
= font
->GSUB_Table
;
5717 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5720 TRACE("Script not found\n");
5723 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5726 TRACE("Language not found\n");
5729 feature
= GSUB_get_feature(header
, language
, "vrt2");
5731 feature
= GSUB_get_feature(header
, language
, "vert");
5734 TRACE("vrt2/vert feature not found\n");
5737 return GSUB_apply_feature(header
, feature
, glyph
);
5740 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5744 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5745 WCHAR wc
= (WCHAR
)glyph
;
5747 BOOL
*default_used_pointer
;
5750 default_used_pointer
= NULL
;
5751 default_used
= FALSE
;
5752 if (codepage_sets_default_used(font
->codepage
))
5753 default_used_pointer
= &default_used
;
5754 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5756 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
5757 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
5762 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5763 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5767 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5769 if (glyph
< 0x100) glyph
+= 0xf000;
5770 /* there is a number of old pre-Unicode "broken" TTFs, which
5771 do have symbols at U+00XX instead of U+f0XX */
5772 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5773 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5775 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5780 /*************************************************************
5781 * freetype_GetGlyphIndices
5783 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5785 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5788 BOOL got_default
= FALSE
;
5792 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5793 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5796 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5798 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5803 EnterCriticalSection( &freetype_cs
);
5805 for(i
= 0; i
< count
; i
++)
5807 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5812 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5814 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5815 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5820 get_text_metrics(physdev
->font
, &textm
);
5821 default_char
= textm
.tmDefaultChar
;
5825 pgi
[i
] = default_char
;
5828 LeaveCriticalSection( &freetype_cs
);
5832 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5834 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5835 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5838 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5840 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5841 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5844 static inline BYTE
get_max_level( UINT format
)
5848 case GGO_GRAY2_BITMAP
: return 4;
5849 case GGO_GRAY4_BITMAP
: return 16;
5850 case GGO_GRAY8_BITMAP
: return 64;
5855 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5857 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5858 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
5861 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5862 FT_Face ft_face
= incoming_font
->ft_face
;
5863 GdiFont
*font
= incoming_font
;
5864 FT_UInt glyph_index
;
5865 DWORD width
, height
, pitch
, needed
= 0;
5866 FT_Bitmap ft_bitmap
;
5868 INT left
, right
, top
= 0, bottom
= 0, adv
;
5870 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5871 double widthRatio
= 1.0;
5872 FT_Matrix transMat
= identityMat
;
5873 FT_Matrix transMatUnrotated
;
5874 BOOL needsTransform
= FALSE
;
5875 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5876 UINT original_index
;
5877 FT_Fixed avgAdvance
= 0;
5879 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5880 buflen
, buf
, lpmat
);
5882 TRACE("font transform %f %f %f %f\n",
5883 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5884 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5886 if(format
& GGO_GLYPH_INDEX
) {
5887 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5888 original_index
= glyph
;
5889 format
&= ~GGO_GLYPH_INDEX
;
5891 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5892 ft_face
= font
->ft_face
;
5893 original_index
= glyph_index
;
5896 if(format
& GGO_UNHINTED
) {
5897 load_flags
|= FT_LOAD_NO_HINTING
;
5898 format
&= ~GGO_UNHINTED
;
5901 /* tategaki never appears to happen to lower glyph index */
5902 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5905 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5906 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5907 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5908 font
->gmsize
* sizeof(GM
*));
5910 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5911 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5913 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5914 *abc
= FONT_GM(font
,original_index
)->abc
;
5915 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5916 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5917 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5918 return 1; /* FIXME */
5922 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5923 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5925 /* Scaling factor */
5930 get_text_metrics(font
, &tm
);
5932 widthRatio
= (double)font
->aveWidth
;
5933 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5936 widthRatio
= font
->scale_y
;
5938 /* Scaling transform */
5939 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5942 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5945 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5947 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5948 needsTransform
= TRUE
;
5951 /* Slant transform */
5952 if (font
->fake_italic
) {
5955 slantMat
.xx
= (1 << 16);
5956 slantMat
.xy
= ((1 << 16) >> 2);
5958 slantMat
.yy
= (1 << 16);
5959 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5960 needsTransform
= TRUE
;
5963 /* Rotation transform */
5964 transMatUnrotated
= transMat
;
5965 if(font
->orientation
&& !tategaki
) {
5966 FT_Matrix rotationMat
;
5968 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5969 pFT_Vector_Unit(&vecAngle
, angle
);
5970 rotationMat
.xx
= vecAngle
.x
;
5971 rotationMat
.xy
= -vecAngle
.y
;
5972 rotationMat
.yx
= -rotationMat
.xy
;
5973 rotationMat
.yy
= rotationMat
.xx
;
5975 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5976 needsTransform
= TRUE
;
5979 /* World transform */
5980 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5983 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5984 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5985 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5986 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5987 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5988 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5989 needsTransform
= TRUE
;
5992 /* Extra transformation specified by caller */
5993 if (!is_identity_MAT2(lpmat
))
5996 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
5997 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
5998 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
5999 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6000 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6001 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6002 needsTransform
= TRUE
;
6005 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6007 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6010 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6014 if(FT_IS_SCALABLE(incoming_font
->ft_face
)) {
6016 if (get_text_metrics(incoming_font
, &tm
) &&
6017 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6018 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
,
6019 incoming_font
->ft_face
->size
->metrics
.x_scale
);
6020 if (avgAdvance
&& (ft_face
->glyph
->metrics
.horiAdvance
+63) >> 6 == (avgAdvance
*2+63) >> 6)
6021 TRACE("Fixed-pitch full-width character detected\n");
6023 avgAdvance
= 0; /* cancel this feature */
6027 if(!needsTransform
) {
6028 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
6029 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
6031 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
6033 adv
= (INT
)((avgAdvance
+ 32) >> 6) * 2;
6035 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
6036 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
6037 ft_face
->glyph
->metrics
.height
) & -64;
6038 lpgm
->gmCellIncX
= adv
;
6039 lpgm
->gmCellIncY
= 0;
6046 for(xc
= 0; xc
< 2; xc
++) {
6047 for(yc
= 0; yc
< 2; yc
++) {
6048 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
6049 xc
* ft_face
->glyph
->metrics
.width
);
6050 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
6051 yc
* ft_face
->glyph
->metrics
.height
;
6052 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6053 pFT_Vector_Transform(&vec
, &transMat
);
6054 if(xc
== 0 && yc
== 0) {
6055 left
= right
= vec
.x
;
6056 top
= bottom
= vec
.y
;
6058 if(vec
.x
< left
) left
= vec
.x
;
6059 else if(vec
.x
> right
) right
= vec
.x
;
6060 if(vec
.y
< bottom
) bottom
= vec
.y
;
6061 else if(vec
.y
> top
) top
= vec
.y
;
6066 right
= (right
+ 63) & -64;
6067 bottom
= bottom
& -64;
6068 top
= (top
+ 63) & -64;
6070 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6071 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
6073 pFT_Vector_Transform(&vec
, &transMat
);
6074 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6075 if (!avgAdvance
|| vec
.y
)
6076 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6080 pFT_Vector_Transform(&vec
, &transMat
);
6081 lpgm
->gmCellIncX
= ((vec
.x
+32) >> 6) * 2;
6084 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
6086 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6087 if (!avgAdvance
|| vec
.y
)
6088 adv
= (vec
.x
+63) >> 6;
6092 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6093 adv
= ((vec
.x
+32) >> 6) * 2;
6097 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6098 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6099 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
6100 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
6101 abc
->abcA
= left
>> 6;
6102 abc
->abcB
= (right
- left
) >> 6;
6103 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6105 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6106 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6107 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6109 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6110 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6112 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6113 FONT_GM(font
,original_index
)->abc
= *abc
;
6114 FONT_GM(font
,original_index
)->init
= TRUE
;
6117 if(format
== GGO_METRICS
)
6119 return 1; /* FIXME */
6122 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6123 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6125 TRACE("loaded a bitmap\n");
6131 width
= lpgm
->gmBlackBoxX
;
6132 height
= lpgm
->gmBlackBoxY
;
6133 pitch
= ((width
+ 31) >> 5) << 2;
6134 needed
= pitch
* height
;
6136 if(!buf
|| !buflen
) break;
6138 switch(ft_face
->glyph
->format
) {
6139 case ft_glyph_format_bitmap
:
6141 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6142 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
6143 INT h
= ft_face
->glyph
->bitmap
.rows
;
6145 memcpy(dst
, src
, w
);
6146 src
+= ft_face
->glyph
->bitmap
.pitch
;
6152 case ft_glyph_format_outline
:
6153 ft_bitmap
.width
= width
;
6154 ft_bitmap
.rows
= height
;
6155 ft_bitmap
.pitch
= pitch
;
6156 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6157 ft_bitmap
.buffer
= buf
;
6160 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6162 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6164 /* Note: FreeType will only set 'black' bits for us. */
6165 memset(buf
, 0, needed
);
6166 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6170 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6175 case GGO_GRAY2_BITMAP
:
6176 case GGO_GRAY4_BITMAP
:
6177 case GGO_GRAY8_BITMAP
:
6178 case WINE_GGO_GRAY16_BITMAP
:
6180 unsigned int max_level
, row
, col
;
6183 width
= lpgm
->gmBlackBoxX
;
6184 height
= lpgm
->gmBlackBoxY
;
6185 pitch
= (width
+ 3) / 4 * 4;
6186 needed
= pitch
* height
;
6188 if(!buf
|| !buflen
) break;
6190 max_level
= get_max_level( format
);
6192 switch(ft_face
->glyph
->format
) {
6193 case ft_glyph_format_bitmap
:
6195 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6196 INT h
= ft_face
->glyph
->bitmap
.rows
;
6198 memset( buf
, 0, needed
);
6200 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6201 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6202 src
+= ft_face
->glyph
->bitmap
.pitch
;
6207 case ft_glyph_format_outline
:
6209 ft_bitmap
.width
= width
;
6210 ft_bitmap
.rows
= height
;
6211 ft_bitmap
.pitch
= pitch
;
6212 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6213 ft_bitmap
.buffer
= buf
;
6216 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6218 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6220 memset(ft_bitmap
.buffer
, 0, buflen
);
6222 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6224 if (max_level
!= 255)
6226 for (row
= 0, start
= buf
; row
< height
; row
++)
6228 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6229 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6237 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6243 case WINE_GGO_HRGB_BITMAP
:
6244 case WINE_GGO_HBGR_BITMAP
:
6245 case WINE_GGO_VRGB_BITMAP
:
6246 case WINE_GGO_VBGR_BITMAP
:
6247 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6249 switch (ft_face
->glyph
->format
)
6251 case FT_GLYPH_FORMAT_BITMAP
:
6256 width
= lpgm
->gmBlackBoxX
;
6257 height
= lpgm
->gmBlackBoxY
;
6259 needed
= pitch
* height
;
6261 if (!buf
|| !buflen
) break;
6263 memset(buf
, 0, buflen
);
6265 src
= ft_face
->glyph
->bitmap
.buffer
;
6266 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6268 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6271 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6273 if ( src
[x
/ 8] & masks
[x
% 8] )
6274 ((unsigned int *)dst
)[x
] = ~0u;
6283 case FT_GLYPH_FORMAT_OUTLINE
:
6287 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6288 INT x_shift
, y_shift
;
6290 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6291 FT_Render_Mode render_mode
=
6292 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6293 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6295 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6297 if ( render_mode
== FT_RENDER_MODE_LCD
)
6299 lpgm
->gmBlackBoxX
+= 2;
6300 lpgm
->gmptGlyphOrigin
.x
-= 1;
6304 lpgm
->gmBlackBoxY
+= 2;
6305 lpgm
->gmptGlyphOrigin
.y
+= 1;
6309 width
= lpgm
->gmBlackBoxX
;
6310 height
= lpgm
->gmBlackBoxY
;
6312 needed
= pitch
* height
;
6314 if (!buf
|| !buflen
) break;
6316 memset(buf
, 0, buflen
);
6318 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6320 if ( needsTransform
)
6321 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6323 if ( pFT_Library_SetLcdFilter
)
6324 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6325 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6327 src
= ft_face
->glyph
->bitmap
.buffer
;
6328 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6329 src_width
= ft_face
->glyph
->bitmap
.width
;
6330 src_height
= ft_face
->glyph
->bitmap
.rows
;
6332 if ( render_mode
== FT_RENDER_MODE_LCD
)
6340 rgb_interval
= src_pitch
;
6345 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6346 if ( x_shift
< 0 ) x_shift
= 0;
6347 if ( x_shift
+ (src_width
/ hmul
) > width
)
6348 x_shift
= width
- (src_width
/ hmul
);
6350 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6351 if ( y_shift
< 0 ) y_shift
= 0;
6352 if ( y_shift
+ (src_height
/ vmul
) > height
)
6353 y_shift
= height
- (src_height
/ vmul
);
6355 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
6356 while ( src_height
)
6358 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
6362 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6363 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6364 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6365 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6369 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6370 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6371 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6372 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6375 src
+= src_pitch
* vmul
;
6384 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6396 int contour
, point
= 0, first_pt
;
6397 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6398 TTPOLYGONHEADER
*pph
;
6400 DWORD pph_start
, cpfx
, type
;
6402 if(buflen
== 0) buf
= NULL
;
6404 if (needsTransform
&& buf
) {
6405 pFT_Outline_Transform(outline
, &transMat
);
6408 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6409 /* Ignore contours containing one point */
6410 if(point
== outline
->contours
[contour
]) {
6416 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6419 pph
->dwType
= TT_POLYGON_TYPE
;
6420 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6422 needed
+= sizeof(*pph
);
6424 while(point
<= outline
->contours
[contour
]) {
6425 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6426 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6427 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6431 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6434 } while(point
<= outline
->contours
[contour
] &&
6435 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6436 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6437 /* At the end of a contour Windows adds the start point, but
6439 if(point
> outline
->contours
[contour
] &&
6440 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6442 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6444 } else if(point
<= outline
->contours
[contour
] &&
6445 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6446 /* add closing pt for bezier */
6448 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6456 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6459 pph
->cb
= needed
- pph_start
;
6465 /* Convert the quadratic Beziers to cubic Beziers.
6466 The parametric eqn for a cubic Bezier is, from PLRM:
6467 r(t) = at^3 + bt^2 + ct + r0
6468 with the control points:
6473 A quadratic Bezier has the form:
6474 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6476 So equating powers of t leads to:
6477 r1 = 2/3 p1 + 1/3 p0
6478 r2 = 2/3 p1 + 1/3 p2
6479 and of course r0 = p0, r3 = p2
6482 int contour
, point
= 0, first_pt
;
6483 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6484 TTPOLYGONHEADER
*pph
;
6486 DWORD pph_start
, cpfx
, type
;
6487 FT_Vector cubic_control
[4];
6488 if(buflen
== 0) buf
= NULL
;
6490 if (needsTransform
&& buf
) {
6491 pFT_Outline_Transform(outline
, &transMat
);
6494 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6496 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6499 pph
->dwType
= TT_POLYGON_TYPE
;
6500 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6502 needed
+= sizeof(*pph
);
6504 while(point
<= outline
->contours
[contour
]) {
6505 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6506 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6507 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6510 if(type
== TT_PRIM_LINE
) {
6512 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6516 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6519 /* FIXME: Possible optimization in endpoint calculation
6520 if there are two consecutive curves */
6521 cubic_control
[0] = outline
->points
[point
-1];
6522 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6523 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6524 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6525 cubic_control
[0].x
>>= 1;
6526 cubic_control
[0].y
>>= 1;
6528 if(point
+1 > outline
->contours
[contour
])
6529 cubic_control
[3] = outline
->points
[first_pt
];
6531 cubic_control
[3] = outline
->points
[point
+1];
6532 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6533 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6534 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6535 cubic_control
[3].x
>>= 1;
6536 cubic_control
[3].y
>>= 1;
6539 /* r1 = 1/3 p0 + 2/3 p1
6540 r2 = 1/3 p2 + 2/3 p1 */
6541 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6542 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6543 cubic_control
[2] = cubic_control
[1];
6544 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6545 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6546 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6547 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6549 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6550 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6551 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6556 } while(point
<= outline
->contours
[contour
] &&
6557 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6558 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6559 /* At the end of a contour Windows adds the start point,
6560 but only for Beziers and we've already done that.
6562 if(point
<= outline
->contours
[contour
] &&
6563 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6564 /* This is the closing pt of a bezier, but we've already
6565 added it, so just inc point and carry on */
6572 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6575 pph
->cb
= needed
- pph_start
;
6581 FIXME("Unsupported format %d\n", format
);
6587 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6589 FT_Face ft_face
= font
->ft_face
;
6590 FT_WinFNT_HeaderRec winfnt_header
;
6591 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6592 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6593 font
->potm
->otmSize
= size
;
6595 #define TM font->potm->otmTextMetrics
6596 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6598 TM
.tmHeight
= winfnt_header
.pixel_height
;
6599 TM
.tmAscent
= winfnt_header
.ascent
;
6600 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6601 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6602 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6603 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6604 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6605 TM
.tmWeight
= winfnt_header
.weight
;
6607 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6608 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6609 TM
.tmFirstChar
= winfnt_header
.first_char
;
6610 TM
.tmLastChar
= winfnt_header
.last_char
;
6611 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6612 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6613 TM
.tmItalic
= winfnt_header
.italic
;
6614 TM
.tmUnderlined
= font
->underline
;
6615 TM
.tmStruckOut
= font
->strikeout
;
6616 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6617 TM
.tmCharSet
= winfnt_header
.charset
;
6621 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6622 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6623 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6624 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6625 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6626 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6627 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6628 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6630 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6631 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6633 TM
.tmLastChar
= 255;
6634 TM
.tmDefaultChar
= 32;
6635 TM
.tmBreakChar
= 32;
6636 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6637 TM
.tmUnderlined
= font
->underline
;
6638 TM
.tmStruckOut
= font
->strikeout
;
6639 /* NB inverted meaning of TMPF_FIXED_PITCH */
6640 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6641 TM
.tmCharSet
= font
->charset
;
6649 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6651 double scale_x
, scale_y
;
6655 scale_x
= (double)font
->aveWidth
;
6656 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6659 scale_x
= font
->scale_y
;
6661 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6662 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6664 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6665 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6667 SCALE_Y(ptm
->tmHeight
);
6668 SCALE_Y(ptm
->tmAscent
);
6669 SCALE_Y(ptm
->tmDescent
);
6670 SCALE_Y(ptm
->tmInternalLeading
);
6671 SCALE_Y(ptm
->tmExternalLeading
);
6672 SCALE_Y(ptm
->tmOverhang
);
6674 SCALE_X(ptm
->tmAveCharWidth
);
6675 SCALE_X(ptm
->tmMaxCharWidth
);
6681 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6683 double scale_x
, scale_y
;
6687 scale_x
= (double)font
->aveWidth
;
6688 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6691 scale_x
= font
->scale_y
;
6693 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6694 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6696 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6698 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6699 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6701 SCALE_Y(potm
->otmAscent
);
6702 SCALE_Y(potm
->otmDescent
);
6703 SCALE_Y(potm
->otmLineGap
);
6704 SCALE_Y(potm
->otmsCapEmHeight
);
6705 SCALE_Y(potm
->otmsXHeight
);
6706 SCALE_Y(potm
->otmrcFontBox
.top
);
6707 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6708 SCALE_X(potm
->otmrcFontBox
.left
);
6709 SCALE_X(potm
->otmrcFontBox
.right
);
6710 SCALE_Y(potm
->otmMacAscent
);
6711 SCALE_Y(potm
->otmMacDescent
);
6712 SCALE_Y(potm
->otmMacLineGap
);
6713 SCALE_X(potm
->otmptSubscriptSize
.x
);
6714 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6715 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6716 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6717 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6718 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6719 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6720 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6721 SCALE_Y(potm
->otmsStrikeoutSize
);
6722 SCALE_Y(potm
->otmsStrikeoutPosition
);
6723 SCALE_Y(potm
->otmsUnderscoreSize
);
6724 SCALE_Y(potm
->otmsUnderscorePosition
);
6730 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6734 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6736 /* Make sure that the font has sane width/height ratio */
6739 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6741 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6746 *ptm
= font
->potm
->otmTextMetrics
;
6747 scale_font_metrics(font
, ptm
);
6751 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6755 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6757 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6763 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6766 FT_Face ft_face
= font
->ft_face
;
6767 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
6769 TT_HoriHeader
*pHori
;
6770 TT_Postscript
*pPost
;
6771 FT_Fixed x_scale
, y_scale
;
6772 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
6774 INT ascent
, descent
;
6776 TRACE("font=%p\n", font
);
6778 if(!FT_IS_SCALABLE(ft_face
))
6781 needed
= sizeof(*font
->potm
);
6783 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6784 family_nameW
= strdupW(font
->name
);
6786 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
6788 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6791 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6792 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
6794 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
6796 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
6798 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6801 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6802 face_nameW
= strdupW(font
->name
);
6804 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
6805 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
6807 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
6809 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6812 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
6813 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6814 full_nameW
= strdupW(fake_nameW
);
6816 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
6818 /* These names should be read from the TT name table */
6820 /* length of otmpFamilyName */
6823 /* length of otmpFaceName */
6826 /* length of otmpStyleName */
6829 /* length of otmpFullName */
6833 x_scale
= ft_face
->size
->metrics
.x_scale
;
6834 y_scale
= ft_face
->size
->metrics
.y_scale
;
6836 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6838 FIXME("Can't find OS/2 table - not TT font?\n");
6842 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6844 FIXME("Can't find HHEA table - not TT font?\n");
6848 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6850 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",
6851 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6852 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6853 pOS2
->xAvgCharWidth
,
6854 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6855 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6856 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6858 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6859 font
->potm
->otmSize
= needed
;
6861 #define TM font->potm->otmTextMetrics
6863 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6864 ascent
= pHori
->Ascender
;
6865 descent
= -pHori
->Descender
;
6867 ascent
= pOS2
->usWinAscent
;
6868 descent
= pOS2
->usWinDescent
;
6871 font
->ntmCellHeight
= ascent
+ descent
;
6872 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6875 TM
.tmAscent
= font
->yMax
;
6876 TM
.tmDescent
= -font
->yMin
;
6877 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6879 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
6880 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
6881 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
6882 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
6885 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6888 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6890 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
6891 ((ascent
+ descent
) -
6892 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
6894 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
6895 if (TM
.tmAveCharWidth
== 0) {
6896 TM
.tmAveCharWidth
= 1;
6898 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
6899 TM
.tmWeight
= FW_REGULAR
;
6900 if (font
->fake_bold
)
6901 TM
.tmWeight
= FW_BOLD
;
6904 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6906 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6907 TM
.tmWeight
= pOS2
->usWeightClass
;
6909 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6910 TM
.tmWeight
= pOS2
->usWeightClass
;
6913 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6914 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6915 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6916 * symbol range to 0 - f0ff
6919 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6924 case 1257: /* Baltic */
6925 TM
.tmLastChar
= 0xf8fd;
6928 TM
.tmLastChar
= 0xf0ff;
6930 TM
.tmBreakChar
= 0x20;
6931 TM
.tmDefaultChar
= 0x1f;
6935 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6936 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6938 if(pOS2
->usFirstCharIndex
<= 1)
6939 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6940 else if (pOS2
->usFirstCharIndex
> 0xff)
6941 TM
.tmBreakChar
= 0x20;
6943 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6944 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6946 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6947 TM
.tmUnderlined
= font
->underline
;
6948 TM
.tmStruckOut
= font
->strikeout
;
6950 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6951 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6952 (pOS2
->version
== 0xFFFFU
||
6953 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6954 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6956 TM
.tmPitchAndFamily
= 0;
6958 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6960 case PAN_FAMILY_SCRIPT
:
6961 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6964 case PAN_FAMILY_DECORATIVE
:
6965 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6970 case PAN_FAMILY_TEXT_DISPLAY
:
6971 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6972 /* which is clearly not what the panose spec says. */
6974 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6975 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6976 TM
.tmPitchAndFamily
= FF_MODERN
;
6979 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6984 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6987 case PAN_SERIF_COVE
:
6988 case PAN_SERIF_OBTUSE_COVE
:
6989 case PAN_SERIF_SQUARE_COVE
:
6990 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
6991 case PAN_SERIF_SQUARE
:
6992 case PAN_SERIF_THIN
:
6993 case PAN_SERIF_BONE
:
6994 case PAN_SERIF_EXAGGERATED
:
6995 case PAN_SERIF_TRIANGLE
:
6996 TM
.tmPitchAndFamily
|= FF_ROMAN
;
6999 case PAN_SERIF_NORMAL_SANS
:
7000 case PAN_SERIF_OBTUSE_SANS
:
7001 case PAN_SERIF_PERP_SANS
:
7002 case PAN_SERIF_FLARED
:
7003 case PAN_SERIF_ROUNDED
:
7004 TM
.tmPitchAndFamily
|= FF_SWISS
;
7011 if(FT_IS_SCALABLE(ft_face
))
7012 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7014 if(FT_IS_SFNT(ft_face
))
7016 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7017 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7019 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7022 TM
.tmCharSet
= font
->charset
;
7024 font
->potm
->otmFiller
= 0;
7025 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7026 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7027 font
->potm
->otmfsType
= pOS2
->fsType
;
7028 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7029 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7030 font
->potm
->otmItalicAngle
= 0; /* POST table */
7031 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7032 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
7033 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
7034 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
7035 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
7036 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
7037 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
7038 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
7039 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
7040 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
7041 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7042 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7043 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7044 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7045 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
7046 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
7047 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
7048 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
7049 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
7050 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
7051 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
7052 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
7053 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
7054 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
7056 font
->potm
->otmsUnderscoreSize
= 0;
7057 font
->potm
->otmsUnderscorePosition
= 0;
7059 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
7060 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
7064 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7065 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7066 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7067 strcpyW((WCHAR
*)cp
, family_nameW
);
7069 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7070 strcpyW((WCHAR
*)cp
, style_nameW
);
7072 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7073 strcpyW((WCHAR
*)cp
, face_nameW
);
7075 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7076 strcpyW((WCHAR
*)cp
, full_nameW
);
7080 HeapFree(GetProcessHeap(), 0, style_nameW
);
7081 HeapFree(GetProcessHeap(), 0, family_nameW
);
7082 HeapFree(GetProcessHeap(), 0, face_nameW
);
7083 HeapFree(GetProcessHeap(), 0, full_nameW
);
7087 /*************************************************************
7088 * freetype_GetGlyphOutline
7090 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7091 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7093 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7099 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7100 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7104 EnterCriticalSection( &freetype_cs
);
7105 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7106 LeaveCriticalSection( &freetype_cs
);
7110 /*************************************************************
7111 * freetype_GetTextMetrics
7113 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7115 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7120 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7121 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7125 EnterCriticalSection( &freetype_cs
);
7126 ret
= get_text_metrics( physdev
->font
, metrics
);
7127 LeaveCriticalSection( &freetype_cs
);
7131 /*************************************************************
7132 * freetype_GetOutlineTextMetrics
7134 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7136 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7141 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7142 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7145 TRACE("font=%p\n", physdev
->font
);
7147 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7150 EnterCriticalSection( &freetype_cs
);
7152 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7154 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7156 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7157 scale_outline_font_metrics(physdev
->font
, potm
);
7159 ret
= physdev
->font
->potm
->otmSize
;
7161 LeaveCriticalSection( &freetype_cs
);
7165 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7167 child
->font
= alloc_font();
7168 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7169 if(!child
->font
->ft_face
)
7171 free_font(child
->font
);
7176 child
->font
->font_desc
= font
->font_desc
;
7177 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7178 child
->font
->orientation
= font
->orientation
;
7179 child
->font
->scale_y
= font
->scale_y
;
7180 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7181 child
->font
->base_font
= font
;
7182 TRACE("created child font %p for base %p\n", child
->font
, font
);
7186 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
7189 CHILD_FONT
*child_font
;
7192 font
= font
->base_font
;
7194 *linked_font
= font
;
7196 if((*glyph
= get_glyph_index(font
, c
)))
7198 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7202 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7204 if(!child_font
->font
)
7205 if(!load_child_font(font
, child_font
))
7208 if(!child_font
->font
->ft_face
)
7210 g
= get_glyph_index(child_font
->font
, c
);
7211 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7215 *linked_font
= child_font
->font
;
7222 /*************************************************************
7223 * freetype_GetCharWidth
7225 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7227 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7231 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7235 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7236 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7239 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7242 EnterCriticalSection( &freetype_cs
);
7243 for(c
= firstChar
; c
<= lastChar
; c
++) {
7244 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7245 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7247 LeaveCriticalSection( &freetype_cs
);
7251 /*************************************************************
7252 * freetype_GetCharABCWidths
7254 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7256 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7259 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7263 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7264 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7267 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7270 EnterCriticalSection( &freetype_cs
);
7272 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7273 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7275 LeaveCriticalSection( &freetype_cs
);
7279 /*************************************************************
7280 * freetype_GetCharABCWidthsI
7282 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7284 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7287 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7291 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7292 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7295 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7299 EnterCriticalSection( &freetype_cs
);
7301 for(c
= 0; c
< count
; c
++, buffer
++)
7302 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7303 &gm
, buffer
, 0, NULL
, &identity
);
7305 LeaveCriticalSection( &freetype_cs
);
7309 /*************************************************************
7310 * freetype_GetTextExtentExPoint
7312 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7314 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7318 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7322 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7323 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7326 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7329 EnterCriticalSection( &freetype_cs
);
7331 for (idx
= pos
= 0; idx
< count
; idx
++)
7333 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7334 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7338 LeaveCriticalSection( &freetype_cs
);
7342 /*************************************************************
7343 * freetype_GetTextExtentExPointI
7345 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7347 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7351 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7355 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7356 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7359 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7362 EnterCriticalSection( &freetype_cs
);
7364 for (idx
= pos
= 0; idx
< count
; idx
++)
7366 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7367 &gm
, &abc
, 0, NULL
, &identity
);
7368 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7372 LeaveCriticalSection( &freetype_cs
);
7376 /*************************************************************
7377 * freetype_GetFontData
7379 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7381 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7385 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7386 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7389 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7390 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7391 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7393 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7396 /*************************************************************
7397 * freetype_GetTextFace
7399 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7402 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7406 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7407 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7410 n
= strlenW(physdev
->font
->name
) + 1;
7413 lstrcpynW(str
, physdev
->font
->name
, count
);
7419 /*************************************************************
7420 * freetype_GetTextCharsetInfo
7422 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7424 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7428 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7429 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7431 if (fs
) *fs
= physdev
->font
->fs
;
7432 return physdev
->font
->charset
;
7435 /* Retrieve a list of supported Unicode ranges for a given font.
7436 * Can be called with NULL gs to calculate the buffer size. Returns
7437 * the number of ranges found.
7439 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7441 DWORD num_ranges
= 0;
7443 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7446 FT_ULong char_code
, char_code_prev
;
7449 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7451 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7452 face
->num_glyphs
, glyph_code
, char_code
);
7454 if (!glyph_code
) return 0;
7458 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7459 gs
->ranges
[0].cGlyphs
= 0;
7460 gs
->cGlyphsSupported
= 0;
7466 if (char_code
< char_code_prev
)
7468 ERR("expected increasing char code from FT_Get_Next_Char\n");
7471 if (char_code
- char_code_prev
> 1)
7476 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7477 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7478 gs
->cGlyphsSupported
++;
7483 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7484 gs
->cGlyphsSupported
++;
7486 char_code_prev
= char_code
;
7487 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7491 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7496 /*************************************************************
7497 * freetype_GetFontUnicodeRanges
7499 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7501 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7502 DWORD size
, num_ranges
;
7506 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7507 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7510 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7511 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7514 glyphset
->cbThis
= size
;
7515 glyphset
->cRanges
= num_ranges
;
7516 glyphset
->flAccel
= 0;
7521 /*************************************************************
7522 * freetype_FontIsLinked
7524 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7526 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7531 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7532 return dev
->funcs
->pFontIsLinked( dev
);
7536 EnterCriticalSection( &freetype_cs
);
7537 ret
= !list_empty(&physdev
->font
->child_fonts
);
7538 LeaveCriticalSection( &freetype_cs
);
7542 /*************************************************************************
7543 * GetRasterizerCaps (GDI32.@)
7545 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7547 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7548 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7549 lprs
->nLanguageID
= 0;
7553 /*************************************************************
7554 * freetype_GdiRealizationInfo
7556 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7558 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7559 realization_info_t
*info
= ptr
;
7563 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7564 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7567 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7570 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7573 info
->cache_num
= physdev
->font
->cache_num
;
7574 info
->unknown2
= -1;
7578 /*************************************************************************
7579 * Kerning support for TrueType fonts
7581 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7583 struct TT_kern_table
7589 struct TT_kern_subtable
7598 USHORT horizontal
: 1;
7600 USHORT cross_stream
: 1;
7601 USHORT override
: 1;
7602 USHORT reserved1
: 4;
7608 struct TT_format0_kern_subtable
7612 USHORT entrySelector
;
7623 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7624 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7625 const USHORT
*glyph_to_char
,
7626 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7629 const struct TT_kern_pair
*tt_kern_pair
;
7631 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7633 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7635 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7636 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7637 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7639 if (!kern_pair
|| !cPairs
)
7642 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7644 nPairs
= min(nPairs
, cPairs
);
7646 for (i
= 0; i
< nPairs
; i
++)
7648 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7649 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7650 /* this algorithm appears to better match what Windows does */
7651 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7652 if (kern_pair
->iKernAmount
< 0)
7654 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7655 kern_pair
->iKernAmount
-= font
->ppem
;
7657 else if (kern_pair
->iKernAmount
> 0)
7659 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7660 kern_pair
->iKernAmount
+= font
->ppem
;
7662 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7664 TRACE("left %u right %u value %d\n",
7665 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7669 TRACE("copied %u entries\n", nPairs
);
7673 /*************************************************************
7674 * freetype_GetKerningPairs
7676 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7680 const struct TT_kern_table
*tt_kern_table
;
7681 const struct TT_kern_subtable
*tt_kern_subtable
;
7683 USHORT
*glyph_to_char
;
7685 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7687 if (!(font
= physdev
->font
))
7689 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7690 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7694 EnterCriticalSection( &freetype_cs
);
7695 if (font
->total_kern_pairs
!= (DWORD
)-1)
7697 if (cPairs
&& kern_pair
)
7699 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7700 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7702 else cPairs
= font
->total_kern_pairs
;
7704 LeaveCriticalSection( &freetype_cs
);
7708 font
->total_kern_pairs
= 0;
7710 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7712 if (length
== GDI_ERROR
)
7714 TRACE("no kerning data in the font\n");
7715 LeaveCriticalSection( &freetype_cs
);
7719 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7722 WARN("Out of memory\n");
7723 LeaveCriticalSection( &freetype_cs
);
7727 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7729 /* build a glyph index to char code map */
7730 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7733 WARN("Out of memory allocating a glyph index to char code map\n");
7734 HeapFree(GetProcessHeap(), 0, buf
);
7735 LeaveCriticalSection( &freetype_cs
);
7739 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7745 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7747 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7748 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7752 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7754 /* FIXME: This doesn't match what Windows does: it does some fancy
7755 * things with duplicate glyph index to char code mappings, while
7756 * we just avoid overriding existing entries.
7758 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7759 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7761 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7768 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7769 for (n
= 0; n
<= 65535; n
++)
7770 glyph_to_char
[n
] = (USHORT
)n
;
7773 tt_kern_table
= buf
;
7774 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7775 TRACE("version %u, nTables %u\n",
7776 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7778 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7780 for (i
= 0; i
< nTables
; i
++)
7782 struct TT_kern_subtable tt_kern_subtable_copy
;
7784 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7785 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7786 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7788 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7789 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7790 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7792 /* According to the TrueType specification this is the only format
7793 * that will be properly interpreted by Windows and OS/2
7795 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7797 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7799 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7800 glyph_to_char
, NULL
, 0);
7801 font
->total_kern_pairs
+= new_chunk
;
7803 if (!font
->kern_pairs
)
7804 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7805 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7807 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7808 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7810 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7811 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7814 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7816 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7819 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7820 HeapFree(GetProcessHeap(), 0, buf
);
7822 if (cPairs
&& kern_pair
)
7824 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7825 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7827 else cPairs
= font
->total_kern_pairs
;
7829 LeaveCriticalSection( &freetype_cs
);
7833 static const struct gdi_dc_funcs freetype_funcs
=
7835 NULL
, /* pAbortDoc */
7836 NULL
, /* pAbortPath */
7837 NULL
, /* pAlphaBlend */
7838 NULL
, /* pAngleArc */
7841 NULL
, /* pBeginPath */
7842 NULL
, /* pBlendImage */
7844 NULL
, /* pCloseFigure */
7845 NULL
, /* pCreateCompatibleDC */
7846 freetype_CreateDC
, /* pCreateDC */
7847 freetype_DeleteDC
, /* pDeleteDC */
7848 NULL
, /* pDeleteObject */
7849 NULL
, /* pDeviceCapabilities */
7850 NULL
, /* pEllipse */
7852 NULL
, /* pEndPage */
7853 NULL
, /* pEndPath */
7854 freetype_EnumFonts
, /* pEnumFonts */
7855 NULL
, /* pEnumICMProfiles */
7856 NULL
, /* pExcludeClipRect */
7857 NULL
, /* pExtDeviceMode */
7858 NULL
, /* pExtEscape */
7859 NULL
, /* pExtFloodFill */
7860 NULL
, /* pExtSelectClipRgn */
7861 NULL
, /* pExtTextOut */
7862 NULL
, /* pFillPath */
7863 NULL
, /* pFillRgn */
7864 NULL
, /* pFlattenPath */
7865 freetype_FontIsLinked
, /* pFontIsLinked */
7866 NULL
, /* pFrameRgn */
7867 NULL
, /* pGdiComment */
7868 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7869 NULL
, /* pGetBoundsRect */
7870 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7871 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7872 freetype_GetCharWidth
, /* pGetCharWidth */
7873 NULL
, /* pGetDeviceCaps */
7874 NULL
, /* pGetDeviceGammaRamp */
7875 freetype_GetFontData
, /* pGetFontData */
7876 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7877 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7878 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7879 NULL
, /* pGetICMProfile */
7880 NULL
, /* pGetImage */
7881 freetype_GetKerningPairs
, /* pGetKerningPairs */
7882 NULL
, /* pGetNearestColor */
7883 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7884 NULL
, /* pGetPixel */
7885 NULL
, /* pGetSystemPaletteEntries */
7886 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7887 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7888 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7889 freetype_GetTextFace
, /* pGetTextFace */
7890 freetype_GetTextMetrics
, /* pGetTextMetrics */
7891 NULL
, /* pGradientFill */
7892 NULL
, /* pIntersectClipRect */
7893 NULL
, /* pInvertRgn */
7895 NULL
, /* pModifyWorldTransform */
7897 NULL
, /* pOffsetClipRgn */
7898 NULL
, /* pOffsetViewportOrg */
7899 NULL
, /* pOffsetWindowOrg */
7900 NULL
, /* pPaintRgn */
7903 NULL
, /* pPolyBezier */
7904 NULL
, /* pPolyBezierTo */
7905 NULL
, /* pPolyDraw */
7906 NULL
, /* pPolyPolygon */
7907 NULL
, /* pPolyPolyline */
7908 NULL
, /* pPolygon */
7909 NULL
, /* pPolyline */
7910 NULL
, /* pPolylineTo */
7911 NULL
, /* pPutImage */
7912 NULL
, /* pRealizeDefaultPalette */
7913 NULL
, /* pRealizePalette */
7914 NULL
, /* pRectangle */
7915 NULL
, /* pResetDC */
7916 NULL
, /* pRestoreDC */
7917 NULL
, /* pRoundRect */
7919 NULL
, /* pScaleViewportExt */
7920 NULL
, /* pScaleWindowExt */
7921 NULL
, /* pSelectBitmap */
7922 NULL
, /* pSelectBrush */
7923 NULL
, /* pSelectClipPath */
7924 freetype_SelectFont
, /* pSelectFont */
7925 NULL
, /* pSelectPalette */
7926 NULL
, /* pSelectPen */
7927 NULL
, /* pSetArcDirection */
7928 NULL
, /* pSetBkColor */
7929 NULL
, /* pSetBkMode */
7930 NULL
, /* pSetDCBrushColor */
7931 NULL
, /* pSetDCPenColor */
7932 NULL
, /* pSetDIBColorTable */
7933 NULL
, /* pSetDIBitsToDevice */
7934 NULL
, /* pSetDeviceClipping */
7935 NULL
, /* pSetDeviceGammaRamp */
7936 NULL
, /* pSetLayout */
7937 NULL
, /* pSetMapMode */
7938 NULL
, /* pSetMapperFlags */
7939 NULL
, /* pSetPixel */
7940 NULL
, /* pSetPolyFillMode */
7941 NULL
, /* pSetROP2 */
7942 NULL
, /* pSetRelAbs */
7943 NULL
, /* pSetStretchBltMode */
7944 NULL
, /* pSetTextAlign */
7945 NULL
, /* pSetTextCharacterExtra */
7946 NULL
, /* pSetTextColor */
7947 NULL
, /* pSetTextJustification */
7948 NULL
, /* pSetViewportExt */
7949 NULL
, /* pSetViewportOrg */
7950 NULL
, /* pSetWindowExt */
7951 NULL
, /* pSetWindowOrg */
7952 NULL
, /* pSetWorldTransform */
7953 NULL
, /* pStartDoc */
7954 NULL
, /* pStartPage */
7955 NULL
, /* pStretchBlt */
7956 NULL
, /* pStretchDIBits */
7957 NULL
, /* pStrokeAndFillPath */
7958 NULL
, /* pStrokePath */
7959 NULL
, /* pUnrealizePalette */
7960 NULL
, /* pWidenPath */
7961 NULL
, /* wine_get_wgl_driver */
7962 GDI_PRIORITY_FONT_DRV
/* priority */
7965 #else /* HAVE_FREETYPE */
7967 /*************************************************************************/
7969 BOOL
WineEngInit(void)
7974 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7976 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7980 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7982 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7986 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
7988 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
7992 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
7993 LPCWSTR font_file
, LPCWSTR font_path
)
7999 /*************************************************************************
8000 * GetRasterizerCaps (GDI32.@)
8002 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8004 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8006 lprs
->nLanguageID
= 0;
8010 #endif /* HAVE_FREETYPE */