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
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1310 TRACE("Font %s already in list, refcount now %d\n",
1311 debugstr_w(face
->file
), cursor
->refcount
);
1314 if (face
->font_version
<= cursor
->font_version
)
1316 TRACE("Original font %s is newer so skipping %s\n",
1317 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1322 TRACE("Replacing original %s with %s\n",
1323 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1324 list_add_before( &cursor
->entry
, &face
->entry
);
1325 face
->family
= family
;
1328 release_face( cursor
);
1333 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1335 if (style_order( face
) < style_order( cursor
)) break;
1338 list_add_before( &cursor
->entry
, &face
->entry
);
1339 face
->family
= family
;
1345 /****************************************************************
1346 * NB This function stores the ptrs to the strings to save copying.
1347 * Don't free them after calling.
1349 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1351 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1352 family
->refcount
= 1;
1353 family
->FamilyName
= name
;
1354 family
->EnglishName
= english_name
;
1355 list_init( &family
->faces
);
1356 family
->replacement
= &family
->faces
;
1357 list_add_tail( &font_list
, &family
->entry
);
1362 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1364 DWORD type
, size
= sizeof(DWORD
);
1366 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1367 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1370 return ERROR_BAD_CONFIGURATION
;
1372 return ERROR_SUCCESS
;
1375 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1377 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1380 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1382 DWORD needed
, strike_index
= 0;
1385 /* If we have a File Name key then this is a real font, not just the parent
1386 key of a bunch of non-scalable strikes */
1387 needed
= buffer_size
;
1388 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1391 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1392 face
->cached_enum_data
= NULL
;
1393 face
->family
= NULL
;
1396 face
->file
= strdupW( buffer
);
1397 face
->StyleName
= strdupW(face_name
);
1399 needed
= buffer_size
;
1400 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1401 face
->FullName
= strdupW( buffer
);
1403 face
->FullName
= NULL
;
1405 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1406 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1407 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1408 reg_load_dword(hkey_face
, face_flags_value
, (DWORD
*)&face
->flags
);
1410 needed
= sizeof(face
->fs
);
1411 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1413 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1415 face
->scalable
= TRUE
;
1416 memset(&face
->size
, 0, sizeof(face
->size
));
1420 face
->scalable
= FALSE
;
1421 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1422 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1423 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1424 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1425 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1427 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1428 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1429 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1432 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1433 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1434 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1435 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1437 if (insert_face_in_family_list(face
, family
))
1438 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1440 release_face( face
);
1443 /* load bitmap strikes */
1445 needed
= buffer_size
;
1446 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1448 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1450 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1451 RegCloseKey(hkey_strike
);
1453 needed
= buffer_size
;
1457 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1459 DWORD size
, family_index
= 0;
1464 size
= sizeof(buffer
);
1465 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1467 WCHAR
*english_family
= NULL
;
1468 WCHAR
*family_name
= strdupW( buffer
);
1469 DWORD face_index
= 0;
1471 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1472 TRACE("opened family key %s\n", debugstr_w(family_name
));
1473 size
= sizeof(buffer
);
1474 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1475 english_family
= strdupW( buffer
);
1477 family
= create_family(family_name
, english_family
);
1481 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1482 subst
->from
.name
= strdupW(english_family
);
1483 subst
->from
.charset
= -1;
1484 subst
->to
.name
= strdupW(family_name
);
1485 subst
->to
.charset
= -1;
1486 add_font_subst(&font_subst_list
, subst
, 0);
1489 size
= sizeof(buffer
);
1490 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1492 WCHAR
*face_name
= strdupW( buffer
);
1495 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1497 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1498 RegCloseKey(hkey_face
);
1500 HeapFree( GetProcessHeap(), 0, face_name
);
1501 size
= sizeof(buffer
);
1503 RegCloseKey(hkey_family
);
1504 release_family( family
);
1505 size
= sizeof(buffer
);
1509 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1512 HKEY hkey_wine_fonts
;
1514 /* We don't want to create the fonts key as volatile, so open this first */
1515 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1516 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1517 if(ret
!= ERROR_SUCCESS
)
1519 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1523 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1524 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1525 RegCloseKey(hkey_wine_fonts
);
1529 static void add_face_to_cache(Face
*face
)
1531 HKEY hkey_family
, hkey_face
;
1532 WCHAR
*face_key_name
;
1534 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1535 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1536 if(face
->family
->EnglishName
)
1537 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1538 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1541 face_key_name
= face
->StyleName
;
1544 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1545 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1546 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1548 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1551 HeapFree(GetProcessHeap(), 0, face_key_name
);
1553 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1554 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1556 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1557 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1559 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1560 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1561 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1562 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1564 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1568 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1569 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1570 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1571 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1572 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1573 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1575 RegCloseKey(hkey_face
);
1576 RegCloseKey(hkey_family
);
1579 static void remove_face_from_cache( Face
*face
)
1583 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1587 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1591 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1592 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1593 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1594 RegDeleteKeyW( hkey_family
, face_key_name
);
1595 HeapFree(GetProcessHeap(), 0, face_key_name
);
1597 RegCloseKey(hkey_family
);
1600 static WCHAR
*prepend_at(WCHAR
*family
)
1607 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1609 strcpyW(str
+ 1, family
);
1610 HeapFree(GetProcessHeap(), 0, family
);
1614 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1616 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1617 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1619 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1625 else if (!strcmpiW( *name
, *english
))
1627 HeapFree( GetProcessHeap(), 0, *english
);
1633 *name
= prepend_at( *name
);
1634 *english
= prepend_at( *english
);
1638 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1641 WCHAR
*name
, *english_name
;
1643 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1645 family
= find_family_from_name( name
);
1649 family
= create_family( name
, english_name
);
1652 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1653 subst
->from
.name
= strdupW( english_name
);
1654 subst
->from
.charset
= -1;
1655 subst
->to
.name
= strdupW( name
);
1656 subst
->to
.charset
= -1;
1657 add_font_subst( &font_subst_list
, subst
, 0 );
1662 HeapFree( GetProcessHeap(), 0, name
);
1663 HeapFree( GetProcessHeap(), 0, english_name
);
1670 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1672 FT_Fixed version
= 0;
1675 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1676 if (header
) version
= header
->Font_Revision
;
1681 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1684 FT_ULong table_size
= 0;
1686 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1687 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1688 if (flags
== 0) flags
= NTM_REGULAR
;
1690 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1691 flags
|= NTM_PS_OPENTYPE
;
1696 static inline int get_bitmap_internal_leading( FT_Face ft_face
)
1698 int internal_leading
= 0;
1699 FT_WinFNT_HeaderRec winfnt_header
;
1701 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1702 internal_leading
= winfnt_header
.internal_leading
;
1704 return internal_leading
;
1707 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1712 FT_WinFNT_HeaderRec winfnt_header
;
1715 memset( fs
, 0, sizeof(*fs
) );
1717 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1720 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1721 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1722 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1723 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1725 if (os2
->version
== 0)
1727 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1728 fs
->fsCsb
[0] = FS_LATIN1
;
1730 fs
->fsCsb
[0] = FS_SYMBOL
;
1734 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1735 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1740 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1742 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1743 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1744 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1749 if (fs
->fsCsb
[0] == 0)
1751 /* let's see if we can find any interesting cmaps */
1752 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1754 switch (ft_face
->charmaps
[i
]->encoding
)
1756 case FT_ENCODING_UNICODE
:
1757 case FT_ENCODING_APPLE_ROMAN
:
1758 fs
->fsCsb
[0] |= FS_LATIN1
;
1760 case FT_ENCODING_MS_SYMBOL
:
1761 fs
->fsCsb
[0] |= FS_SYMBOL
;
1770 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1774 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1775 My_FT_Bitmap_Size
*size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1778 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1779 if (!face
->StyleName
)
1780 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1781 if (!face
->StyleName
)
1783 face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1786 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1787 if (!face
->FullName
)
1788 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
1789 if (flags
& ADDFONT_VERTICAL_FONT
)
1790 face
->FullName
= prepend_at( face
->FullName
);
1796 face
->file
= towstr( CP_UNIXCP
, file
);
1797 face
->font_data_ptr
= NULL
;
1798 face
->font_data_size
= 0;
1799 if (!stat( file
, &st
))
1801 face
->dev
= st
.st_dev
;
1802 face
->ino
= st
.st_ino
;
1808 face
->font_data_ptr
= font_data_ptr
;
1809 face
->font_data_size
= font_data_size
;
1812 face
->face_index
= face_index
;
1813 get_fontsig( ft_face
, &face
->fs
);
1814 face
->ntmFlags
= get_ntm_flags( ft_face
);
1815 face
->font_version
= get_font_version( ft_face
);
1817 if (FT_IS_SCALABLE( ft_face
))
1819 memset( &face
->size
, 0, sizeof(face
->size
) );
1820 face
->scalable
= TRUE
;
1824 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1825 size
->height
, size
->width
, size
->size
>> 6,
1826 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1827 face
->size
.height
= size
->height
;
1828 face
->size
.width
= size
->width
;
1829 face
->size
.size
= size
->size
;
1830 face
->size
.x_ppem
= size
->x_ppem
;
1831 face
->size
.y_ppem
= size
->y_ppem
;
1832 face
->size
.internal_leading
= get_bitmap_internal_leading( ft_face
);
1833 face
->scalable
= FALSE
;
1836 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1837 face
->flags
= flags
;
1838 face
->family
= NULL
;
1839 face
->cached_enum_data
= NULL
;
1841 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1842 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1843 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1844 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1849 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1850 FT_Long face_index
, DWORD flags
)
1855 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
1856 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
1857 if (insert_face_in_family_list( face
, family
))
1859 if (flags
& ADDFONT_ADD_TO_CACHE
)
1860 add_face_to_cache( face
);
1862 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1863 debugstr_w(face
->StyleName
));
1865 release_face( face
);
1866 release_family( family
);
1869 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1870 FT_Long face_index
, BOOL allow_bitmap
)
1878 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1879 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1883 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1884 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1889 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1893 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1894 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
1896 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1900 if (!FT_IS_SFNT( ft_face
))
1902 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1904 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1910 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1911 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1912 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1914 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1915 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1919 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1920 we don't want to load these. */
1921 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1925 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1927 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1933 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1935 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1941 pFT_Done_Face( ft_face
);
1945 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
1948 FT_Long face_index
= 0, num_faces
;
1951 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1952 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1954 #ifdef HAVE_CARBON_CARBON_H
1957 char **mac_list
= expand_mac_font(file
);
1960 BOOL had_one
= FALSE
;
1962 for(cursor
= mac_list
; *cursor
; cursor
++)
1965 AddFontToList(*cursor
, NULL
, 0, flags
);
1966 HeapFree(GetProcessHeap(), 0, *cursor
);
1968 HeapFree(GetProcessHeap(), 0, mac_list
);
1973 #endif /* HAVE_CARBON_CARBON_H */
1976 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
1977 if (!ft_face
) return 0;
1979 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1981 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
1982 pFT_Done_Face(ft_face
);
1986 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
1989 if (FT_HAS_VERTICAL(ft_face
))
1991 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
1992 flags
| ADDFONT_VERTICAL_FONT
);
1996 num_faces
= ft_face
->num_faces
;
1997 pFT_Done_Face(ft_face
);
1998 } while(num_faces
> ++face_index
);
2002 static int remove_font_resource( const char *file
, DWORD flags
)
2004 Family
*family
, *family_next
;
2005 Face
*face
, *face_next
;
2009 if (stat( file
, &st
) == -1) return 0;
2010 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2013 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2015 if (!face
->file
) continue;
2016 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2017 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2019 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2020 release_face( face
);
2024 release_family( family
);
2029 static void DumpFontList(void)
2034 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2035 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2036 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2037 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2039 TRACE(" %d", face
->size
.height
);
2046 /***********************************************************
2047 * The replacement list is a way to map an entire font
2048 * family onto another family. For example adding
2050 * [HKCU\Software\Wine\Fonts\Replacements]
2051 * "Wingdings"="Winedings"
2053 * would enumerate the Winedings font both as Winedings and
2054 * Wingdings. However if a real Wingdings font is present the
2055 * replacement does not take place.
2058 static void LoadReplaceList(void)
2061 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2065 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2066 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2068 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2069 &valuelen
, &datalen
, NULL
, NULL
);
2071 valuelen
++; /* returned value doesn't include room for '\0' */
2072 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2073 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2077 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2078 &dlen
) == ERROR_SUCCESS
) {
2079 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2080 /* "NewName"="Oldname" */
2081 if(!find_family_from_any_name(value
))
2083 Family
* const family
= find_family_from_any_name(data
);
2086 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2087 if (new_family
!= NULL
)
2089 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2090 new_family
->FamilyName
= strdupW(value
);
2091 new_family
->EnglishName
= NULL
;
2092 list_init(&new_family
->faces
);
2093 new_family
->replacement
= &family
->faces
;
2094 list_add_tail(&font_list
, &new_family
->entry
);
2099 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2104 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2106 /* reset dlen and vlen */
2110 HeapFree(GetProcessHeap(), 0, data
);
2111 HeapFree(GetProcessHeap(), 0, value
);
2116 static const WCHAR
*font_links_list
[] =
2118 Lucida_Sans_Unicode
,
2119 Microsoft_Sans_Serif
,
2123 static const struct font_links_defaults_list
2125 /* Keyed off substitution for "MS Shell Dlg" */
2126 const WCHAR
*shelldlg
;
2127 /* Maximum of four substitutes, plus terminating NULL pointer */
2128 const WCHAR
*substitutes
[5];
2129 } font_links_defaults_list
[] =
2131 /* Non East-Asian */
2132 { Tahoma
, /* FIXME unverified ordering */
2133 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2135 /* Below lists are courtesy of
2136 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2140 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2142 /* Chinese Simplified */
2144 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2148 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2150 /* Chinese Traditional */
2152 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2157 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2159 SYSTEM_LINKS
*font_link
;
2161 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2163 if(!strcmpiW(font_link
->font_name
, name
))
2170 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2181 SYSTEM_LINKS
*font_link
;
2183 psub
= get_font_subst(&font_subst_list
, name
, -1);
2184 /* Don't store fonts that are only substitutes for other fonts */
2187 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2191 font_link
= find_font_link(name
);
2192 if (font_link
== NULL
)
2194 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2195 font_link
->font_name
= strdupW(name
);
2196 list_init(&font_link
->links
);
2197 list_add_tail(&system_links
, &font_link
->entry
);
2200 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2201 for (i
= 0; values
[i
] != NULL
; i
++)
2203 const struct list
*face_list
;
2204 CHILD_FONT
*child_font
;
2207 if (!strcmpiW(name
,value
))
2209 psub
= get_font_subst(&font_subst_list
, value
, -1);
2211 value
= psub
->to
.name
;
2212 family
= find_family_from_name(value
);
2216 /* Use first extant filename for this Family */
2217 face_list
= get_face_list_from_family(family
);
2218 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2222 file
= strrchrW(face
->file
, '/');
2231 face
= find_face_from_filename(file
, value
);
2234 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2238 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2239 child_font
->face
= face
;
2240 child_font
->font
= NULL
;
2241 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2242 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2243 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2244 child_font
->face
->face_index
);
2245 list_add_tail(&font_link
->links
, &child_font
->entry
);
2247 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2253 /*************************************************************
2256 static BOOL
init_system_links(void)
2260 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2261 WCHAR
*value
, *data
;
2262 WCHAR
*entry
, *next
;
2263 SYSTEM_LINKS
*font_link
, *system_font_link
;
2264 CHILD_FONT
*child_font
;
2265 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2266 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2267 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2272 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2274 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2275 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2276 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2277 val_len
= max_val
+ 1;
2278 data_len
= max_data
;
2280 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2282 psub
= get_font_subst(&font_subst_list
, value
, -1);
2283 /* Don't store fonts that are only substitutes for other fonts */
2286 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2289 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2290 font_link
->font_name
= strdupW(value
);
2291 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2292 list_init(&font_link
->links
);
2293 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2296 CHILD_FONT
*child_font
;
2298 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2300 next
= entry
+ strlenW(entry
) + 1;
2302 face_name
= strchrW(entry
, ',');
2306 while(isspaceW(*face_name
))
2309 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2311 face_name
= psub
->to
.name
;
2313 face
= find_face_from_filename(entry
, face_name
);
2316 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2320 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2321 child_font
->face
= face
;
2322 child_font
->font
= NULL
;
2323 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2324 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2325 TRACE("Adding file %s index %ld\n",
2326 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2327 list_add_tail(&font_link
->links
, &child_font
->entry
);
2329 list_add_tail(&system_links
, &font_link
->entry
);
2331 val_len
= max_val
+ 1;
2332 data_len
= max_data
;
2335 HeapFree(GetProcessHeap(), 0, value
);
2336 HeapFree(GetProcessHeap(), 0, data
);
2341 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2343 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2347 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2349 const FontSubst
*psub2
;
2350 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2352 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2354 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2355 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2357 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2358 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2360 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2362 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2368 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2371 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2372 system_font_link
->font_name
= strdupW(System
);
2373 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2374 list_init(&system_font_link
->links
);
2376 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2379 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2380 child_font
->face
= face
;
2381 child_font
->font
= NULL
;
2382 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2383 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2384 TRACE("Found Tahoma in %s index %ld\n",
2385 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2386 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2388 font_link
= find_font_link(Tahoma
);
2389 if (font_link
!= NULL
)
2391 CHILD_FONT
*font_link_entry
;
2392 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2394 CHILD_FONT
*new_child
;
2395 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2396 new_child
->face
= font_link_entry
->face
;
2397 new_child
->font
= NULL
;
2398 new_child
->face
->refcount
++;
2399 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2400 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2401 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2404 list_add_tail(&system_links
, &system_font_link
->entry
);
2408 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2411 struct dirent
*dent
;
2412 char path
[MAX_PATH
];
2414 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2416 dir
= opendir(dirname
);
2418 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2421 while((dent
= readdir(dir
)) != NULL
) {
2422 struct stat statbuf
;
2424 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2427 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2429 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2431 if(stat(path
, &statbuf
) == -1)
2433 WARN("Can't stat %s\n", debugstr_a(path
));
2436 if(S_ISDIR(statbuf
.st_mode
))
2437 ReadFontDir(path
, external_fonts
);
2440 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2441 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2442 AddFontToList(path
, NULL
, 0, addfont_flags
);
2449 #ifdef SONAME_LIBFONTCONFIG
2451 static BOOL fontconfig_enabled
;
2453 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2459 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2460 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2462 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2466 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2467 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2468 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2469 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2470 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2476 static void init_fontconfig(void)
2478 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2482 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2486 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2487 LOAD_FUNCPTR(FcConfigSubstitute
);
2488 LOAD_FUNCPTR(FcFontList
);
2489 LOAD_FUNCPTR(FcFontSetDestroy
);
2490 LOAD_FUNCPTR(FcInit
);
2491 LOAD_FUNCPTR(FcObjectSetAdd
);
2492 LOAD_FUNCPTR(FcObjectSetCreate
);
2493 LOAD_FUNCPTR(FcObjectSetDestroy
);
2494 LOAD_FUNCPTR(FcPatternCreate
);
2495 LOAD_FUNCPTR(FcPatternDestroy
);
2496 LOAD_FUNCPTR(FcPatternGetBool
);
2497 LOAD_FUNCPTR(FcPatternGetInteger
);
2498 LOAD_FUNCPTR(FcPatternGetString
);
2503 FcPattern
*pattern
= pFcPatternCreate();
2504 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2505 default_aa_flags
= parse_aa_pattern( pattern
);
2506 pFcPatternDestroy( pattern
);
2507 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2508 fontconfig_enabled
= TRUE
;
2512 static void load_fontconfig_fonts(void)
2521 if (!fontconfig_enabled
) return;
2523 pat
= pFcPatternCreate();
2524 os
= pFcObjectSetCreate();
2525 pFcObjectSetAdd(os
, FC_FILE
);
2526 pFcObjectSetAdd(os
, FC_SCALABLE
);
2527 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2528 pFcObjectSetAdd(os
, FC_RGBA
);
2529 fontset
= pFcFontList(NULL
, pat
, os
);
2530 if(!fontset
) return;
2531 for(i
= 0; i
< fontset
->nfont
; i
++) {
2535 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2538 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2540 /* We're just interested in OT/TT fonts for now, so this hack just
2541 picks up the scalable fonts without extensions .pf[ab] to save time
2542 loading every other font */
2544 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2546 TRACE("not scalable\n");
2550 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2551 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2553 len
= strlen( file
);
2554 if(len
< 4) continue;
2555 ext
= &file
[ len
- 3 ];
2556 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2557 AddFontToList(file
, NULL
, 0,
2558 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2560 pFcFontSetDestroy(fontset
);
2561 pFcObjectSetDestroy(os
);
2562 pFcPatternDestroy(pat
);
2565 #elif defined(HAVE_CARBON_CARBON_H)
2567 static void load_mac_font_callback(const void *value
, void *context
)
2569 CFStringRef pathStr
= value
;
2573 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2574 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2575 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2577 TRACE("font file %s\n", path
);
2578 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2580 HeapFree(GetProcessHeap(), 0, path
);
2583 static void load_mac_fonts(void)
2585 CFStringRef removeDupesKey
;
2586 CFBooleanRef removeDupesValue
;
2587 CFDictionaryRef options
;
2588 CTFontCollectionRef col
;
2590 CFMutableSetRef paths
;
2593 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2594 removeDupesValue
= kCFBooleanTrue
;
2595 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2596 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2597 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2598 if (options
) CFRelease(options
);
2601 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2605 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2609 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2613 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2616 WARN("CFSetCreateMutable failed\n");
2621 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2623 CTFontDescriptorRef desc
;
2632 desc
= CFArrayGetValueAtIndex(descs
, i
);
2634 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2635 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2636 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2637 if (!font
) continue;
2639 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2646 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2648 if (status
!= noErr
) continue;
2650 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2653 ext
= CFURLCopyPathExtension(url
);
2656 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2657 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2666 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2668 if (!path
) continue;
2670 CFSetAddValue(paths
, path
);
2676 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2682 static char *get_data_dir_path( LPCWSTR file
)
2684 char *unix_name
= NULL
;
2685 const char *data_dir
= wine_get_data_dir();
2687 if (!data_dir
) data_dir
= wine_get_build_dir();
2691 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2693 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2694 strcpy(unix_name
, data_dir
);
2695 strcat(unix_name
, "/fonts/");
2697 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2702 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2705 char *unix_name
= get_data_dir_path( file
);
2709 EnterCriticalSection( &freetype_cs
);
2710 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2711 LeaveCriticalSection( &freetype_cs
);
2712 HeapFree(GetProcessHeap(), 0, unix_name
);
2717 static char *get_winfonts_dir_path(LPCWSTR file
)
2719 static const WCHAR slashW
[] = {'\\','\0'};
2720 WCHAR windowsdir
[MAX_PATH
];
2722 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2723 strcatW(windowsdir
, fontsW
);
2724 strcatW(windowsdir
, slashW
);
2725 strcatW(windowsdir
, file
);
2726 return wine_get_unix_file_name( windowsdir
);
2729 static void load_system_fonts(void)
2732 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2733 const WCHAR
* const *value
;
2735 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2738 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2739 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2740 strcatW(windowsdir
, fontsW
);
2741 for(value
= SystemFontValues
; *value
; value
++) {
2742 dlen
= sizeof(data
);
2743 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2747 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2748 if((unixname
= wine_get_unix_file_name(pathW
))) {
2749 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2750 HeapFree(GetProcessHeap(), 0, unixname
);
2753 load_font_from_data_dir(data
);
2760 /*************************************************************
2762 * This adds registry entries for any externally loaded fonts
2763 * (fonts from fontconfig or FontDirs). It also deletes entries
2764 * of no longer existing fonts.
2767 static void update_reg_entries(void)
2769 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2775 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2777 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2778 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2779 ERR("Can't create Windows font reg key\n");
2783 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2784 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2785 ERR("Can't create Windows font reg key\n");
2789 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2790 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2791 ERR("Can't create external font reg key\n");
2795 /* enumerate the fonts and add external ones to the two keys */
2797 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2798 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2800 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
2804 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2805 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2806 strcpyW(valueW
, face
->FullName
);
2810 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2811 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2812 strcpyW(valueW
, family
->FamilyName
);
2815 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
2816 path
= wine_get_dos_file_name( buffer
);
2817 HeapFree( GetProcessHeap(), 0, buffer
);
2821 else if ((file
= strrchrW(face
->file
, '/')))
2826 len
= strlenW(file
) + 1;
2827 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2828 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2829 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
2831 HeapFree(GetProcessHeap(), 0, path
);
2832 HeapFree(GetProcessHeap(), 0, valueW
);
2836 if(external_key
) RegCloseKey(external_key
);
2837 if(win9x_key
) RegCloseKey(win9x_key
);
2838 if(winnt_key
) RegCloseKey(winnt_key
);
2842 static void delete_external_font_keys(void)
2844 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2845 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
2849 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2850 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2851 ERR("Can't create Windows font reg key\n");
2855 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2856 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2857 ERR("Can't create Windows font reg key\n");
2861 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
2862 ERR("Can't create external font reg key\n");
2866 /* Delete all external fonts added last time */
2868 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2869 &valuelen
, &datalen
, NULL
, NULL
);
2870 valuelen
++; /* returned value doesn't include room for '\0' */
2871 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2872 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2874 dlen
= datalen
* sizeof(WCHAR
);
2877 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2878 &dlen
) == ERROR_SUCCESS
) {
2880 RegDeleteValueW(winnt_key
, valueW
);
2881 RegDeleteValueW(win9x_key
, valueW
);
2882 /* reset dlen and vlen */
2886 HeapFree(GetProcessHeap(), 0, data
);
2887 HeapFree(GetProcessHeap(), 0, valueW
);
2889 /* Delete the old external fonts key */
2890 RegCloseKey(external_key
);
2891 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
2894 if(win9x_key
) RegCloseKey(win9x_key
);
2895 if(winnt_key
) RegCloseKey(winnt_key
);
2898 /*************************************************************
2899 * WineEngAddFontResourceEx
2902 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2908 if (ft_handle
) /* do it only if we have freetype up and running */
2912 EnterCriticalSection( &freetype_cs
);
2914 if((unixname
= wine_get_unix_file_name(file
)))
2916 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2918 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2919 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
2920 HeapFree(GetProcessHeap(), 0, unixname
);
2922 if (!ret
&& !strchrW(file
, '\\')) {
2923 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2924 if ((unixname
= get_winfonts_dir_path( file
)))
2926 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2927 HeapFree(GetProcessHeap(), 0, unixname
);
2929 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2930 if (!ret
&& (unixname
= get_data_dir_path( file
)))
2932 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2933 HeapFree(GetProcessHeap(), 0, unixname
);
2937 LeaveCriticalSection( &freetype_cs
);
2942 /*************************************************************
2943 * WineEngAddFontMemResourceEx
2946 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
2950 if (ft_handle
) /* do it only if we have freetype up and running */
2952 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
2954 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
2955 memcpy(pFontCopy
, pbFont
, cbFont
);
2957 EnterCriticalSection( &freetype_cs
);
2958 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
2959 LeaveCriticalSection( &freetype_cs
);
2963 TRACE("AddFontToList failed\n");
2964 HeapFree(GetProcessHeap(), 0, pFontCopy
);
2967 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2968 * For now return something unique but quite random
2970 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
2971 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
2978 /*************************************************************
2979 * WineEngRemoveFontResourceEx
2982 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2988 if (ft_handle
) /* do it only if we have freetype up and running */
2992 EnterCriticalSection( &freetype_cs
);
2994 if ((unixname
= wine_get_unix_file_name(file
)))
2996 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
2998 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
2999 ret
= remove_font_resource( unixname
, addfont_flags
);
3000 HeapFree(GetProcessHeap(), 0, unixname
);
3002 if (!ret
&& !strchrW(file
, '\\'))
3004 if ((unixname
= get_winfonts_dir_path( file
)))
3006 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3007 HeapFree(GetProcessHeap(), 0, unixname
);
3009 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3011 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3012 HeapFree(GetProcessHeap(), 0, unixname
);
3016 LeaveCriticalSection( &freetype_cs
);
3021 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3027 if (!font_file
) return NULL
;
3029 file_len
= strlenW( font_file
);
3031 if (font_path
&& font_path
[0])
3033 int path_len
= strlenW( font_path
);
3034 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3035 if (!fullname
) return NULL
;
3036 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3037 fullname
[path_len
] = '\\';
3038 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3042 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3043 if (!len
) return NULL
;
3044 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3045 if (!fullname
) return NULL
;
3046 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3049 unix_name
= wine_get_unix_file_name( fullname
);
3050 HeapFree( GetProcessHeap(), 0, fullname
);
3054 #include <pshpack1.h>
3057 WORD num_of_resources
;
3061 CHAR dfCopyright
[60];
3067 WORD dfInternalLeading
;
3068 WORD dfExternalLeading
;
3076 BYTE dfPitchAndFamily
;
3087 CHAR szFaceName
[LF_FACESIZE
];
3090 #include <poppack.h>
3092 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3093 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3095 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3097 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3099 WCHAR
*name
, *english_name
;
3101 NEWTEXTMETRICEXW ntm
;
3104 if (!ft_face
) return FALSE
;
3105 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3106 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3107 pFT_Done_Face( ft_face
);
3109 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3110 release_face( face
);
3111 HeapFree( GetProcessHeap(), 0, name
);
3112 HeapFree( GetProcessHeap(), 0, english_name
);
3114 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3116 memset( fd
, 0, sizeof(*fd
) );
3118 fd
->num_of_resources
= 1;
3120 fd
->dfVersion
= 0x200;
3121 fd
->dfSize
= sizeof(*fd
);
3122 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3123 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3124 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3126 fd
->dfHorizRes
= 72;
3127 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3128 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3129 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3130 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3131 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3132 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3133 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3134 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3136 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3137 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3138 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3139 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3140 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3141 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3142 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3143 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3144 fd
->dfWidthBytes
= 0;
3146 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3148 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3153 #define NE_FFLAGS_LIBMODULE 0x8000
3154 #define NE_OSFLAGS_WINDOWS 0x02
3156 static const char dos_string
[0x40] = "This is a TrueType resource file";
3157 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3159 #include <pshpack2.h>
3180 struct ne_typeinfo fontdir_type
;
3181 struct ne_nameinfo fontdir_name
;
3182 struct ne_typeinfo scalable_type
;
3183 struct ne_nameinfo scalable_name
;
3185 BYTE fontdir_res_name
[8];
3188 #include <poppack.h>
3190 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3194 DWORD size
, written
;
3196 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3197 char *font_fileA
, *last_part
, *ext
;
3198 IMAGE_DOS_HEADER dos
;
3199 IMAGE_OS2_HEADER ne
=
3201 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3203 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3204 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3206 struct rsrc_tab rsrc_tab
=
3210 { 0, 0, 0x0c50, 0x2c, 0 },
3212 { 0, 0, 0x0c50, 0x8001, 0 },
3214 { 7,'F','O','N','T','D','I','R'}
3217 memset( &dos
, 0, sizeof(dos
) );
3218 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3219 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3221 /* import name is last part\0, resident name is last part without extension
3222 non-resident name is "FONTRES:" + lfFaceName */
3224 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3225 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3226 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3228 last_part
= strrchr( font_fileA
, '\\' );
3229 if (last_part
) last_part
++;
3230 else last_part
= font_fileA
;
3231 import_name_len
= strlen( last_part
) + 1;
3233 ext
= strchr( last_part
, '.' );
3234 if (ext
) res_name_len
= ext
- last_part
;
3235 else res_name_len
= import_name_len
- 1;
3237 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3239 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3240 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3241 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3242 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3244 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3246 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3247 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3248 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3249 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3251 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3252 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3256 HeapFree( GetProcessHeap(), 0, font_fileA
);
3260 memcpy( ptr
, &dos
, sizeof(dos
) );
3261 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3262 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3264 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3265 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3267 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3268 *ptr
++ = res_name_len
;
3269 memcpy( ptr
, last_part
, res_name_len
);
3271 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3272 *ptr
++ = import_name_len
;
3273 memcpy( ptr
, last_part
, import_name_len
);
3275 ptr
= start
+ ne
.ne_nrestab
;
3276 *ptr
++ = non_res_name_len
;
3277 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3278 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3280 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3281 memcpy( ptr
, font_fileA
, font_file_len
);
3283 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3284 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3286 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3287 if (file
!= INVALID_HANDLE_VALUE
)
3289 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3291 CloseHandle( file
);
3294 HeapFree( GetProcessHeap(), 0, start
);
3295 HeapFree( GetProcessHeap(), 0, font_fileA
);
3300 /*************************************************************
3301 * WineEngCreateScalableFontResource
3304 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3305 LPCWSTR font_file
, LPCWSTR font_path
)
3307 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3308 struct fontdir fontdir
;
3311 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3312 SetLastError( ERROR_INVALID_PARAMETER
);
3315 if (hidden
) fontdir
.dfType
|= 0x80;
3316 ret
= create_fot( resource
, font_file
, &fontdir
);
3319 HeapFree( GetProcessHeap(), 0, unix_name
);
3323 static const struct nls_update_font_list
3325 UINT ansi_cp
, oem_cp
;
3326 const char *oem
, *fixed
, *system
;
3327 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3328 /* these are for font substitutes */
3329 const char *shelldlg
, *tmsrmn
;
3330 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3334 const char *from
, *to
;
3335 } arial_0
, courier_new_0
, times_new_roman_0
;
3336 } nls_update_font_list
[] =
3338 /* Latin 1 (United States) */
3339 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3340 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3341 "Tahoma","Times New Roman",
3342 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3345 /* Latin 1 (Multilingual) */
3346 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3347 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3348 "Tahoma","Times New Roman", /* FIXME unverified */
3349 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3352 /* Eastern Europe */
3353 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3354 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3355 "Tahoma","Times New Roman", /* FIXME unverified */
3356 "Fixedsys,238", "System,238",
3357 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3358 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3359 { "Arial CE,0", "Arial,238" },
3360 { "Courier New CE,0", "Courier New,238" },
3361 { "Times New Roman CE,0", "Times New Roman,238" }
3364 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3365 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3366 "Tahoma","Times New Roman", /* FIXME unverified */
3367 "Fixedsys,204", "System,204",
3368 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3369 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3370 { "Arial Cyr,0", "Arial,204" },
3371 { "Courier New Cyr,0", "Courier New,204" },
3372 { "Times New Roman Cyr,0", "Times New Roman,204" }
3375 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3376 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3377 "Tahoma","Times New Roman", /* FIXME unverified */
3378 "Fixedsys,161", "System,161",
3379 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3380 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3381 { "Arial Greek,0", "Arial,161" },
3382 { "Courier New Greek,0", "Courier New,161" },
3383 { "Times New Roman Greek,0", "Times New Roman,161" }
3386 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3387 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3388 "Tahoma","Times New Roman", /* FIXME unverified */
3389 "Fixedsys,162", "System,162",
3390 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3391 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3392 { "Arial Tur,0", "Arial,162" },
3393 { "Courier New Tur,0", "Courier New,162" },
3394 { "Times New Roman Tur,0", "Times New Roman,162" }
3397 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3398 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3399 "Tahoma","Times New Roman", /* FIXME unverified */
3400 "Fixedsys,177", "System,177",
3401 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3402 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3406 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3407 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3408 "Tahoma","Times New Roman", /* FIXME unverified */
3409 "Fixedsys,178", "System,178",
3410 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3411 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3415 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3416 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3417 "Tahoma","Times New Roman", /* FIXME unverified */
3418 "Fixedsys,186", "System,186",
3419 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3420 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3421 { "Arial Baltic,0", "Arial,186" },
3422 { "Courier New Baltic,0", "Courier New,186" },
3423 { "Times New Roman Baltic,0", "Times New Roman,186" }
3426 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3427 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3428 "Tahoma","Times New Roman", /* FIXME unverified */
3429 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3433 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3434 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3435 "Tahoma","Times New Roman", /* FIXME unverified */
3436 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3440 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3441 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3442 "MS UI Gothic","MS Serif",
3443 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3446 /* Chinese Simplified */
3447 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3449 "SimSun", "NSimSun",
3450 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3454 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3455 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3457 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3460 /* Chinese Traditional */
3461 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3462 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3463 "PMingLiU", "MingLiU",
3464 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3469 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3471 return ( ansi_cp
== 932 /* CP932 for Japanese */
3472 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3473 || ansi_cp
== 949 /* CP949 for Korean */
3474 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3477 static inline HKEY
create_fonts_NT_registry_key(void)
3481 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3482 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3486 static inline HKEY
create_fonts_9x_registry_key(void)
3490 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3491 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3495 static inline HKEY
create_config_fonts_registry_key(void)
3499 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3500 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3504 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3506 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3508 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3509 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3510 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3511 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3514 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3517 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3519 RegDeleteValueA(hkey
, name
);
3522 static void update_font_association_info(UINT current_ansi_codepage
)
3524 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3525 static const char *assoc_charset_subkey
= "Associated Charset";
3527 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3530 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3533 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3535 switch (current_ansi_codepage
)
3538 set_value_key(hsubkey
, "ANSI(00)", "NO");
3539 set_value_key(hsubkey
, "OEM(FF)", "NO");
3540 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3545 set_value_key(hsubkey
, "ANSI(00)", "YES");
3546 set_value_key(hsubkey
, "OEM(FF)", "YES");
3547 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3550 RegCloseKey(hsubkey
);
3553 /* TODO: Associated DefaultFonts */
3559 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3562 static void update_font_info(void)
3564 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3565 char buf
[40], cpbuf
[40];
3568 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3569 DWORD screen_dpi
= 96, font_dpi
= 0;
3572 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3573 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3574 &hkey
) == ERROR_SUCCESS
)
3576 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3580 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3583 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3585 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3586 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3587 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3588 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3589 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3591 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3592 if (is_dbcs_ansi_cp(ansi_cp
))
3593 use_default_fallback
= TRUE
;
3597 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3599 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3604 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3605 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3607 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3608 ansi_cp
, oem_cp
, screen_dpi
);
3610 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3611 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3614 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3618 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3619 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3621 hkey
= create_config_fonts_registry_key();
3622 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3623 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3624 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3627 hkey
= create_fonts_NT_registry_key();
3628 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3631 hkey
= create_fonts_9x_registry_key();
3632 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3635 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3637 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3638 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3639 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3640 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3642 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3643 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3644 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3645 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3646 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3647 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3648 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3649 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3651 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3652 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3653 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3661 /* Delete the FontSubstitutes from other locales */
3662 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3664 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3665 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3666 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3672 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3674 /* update locale dependent font association info in registry.
3675 update only when codepages changed, not logpixels. */
3676 if (strcmp(buf
, cpbuf
) != 0)
3677 update_font_association_info(ansi_cp
);
3680 static BOOL
init_freetype(void)
3682 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3685 "Wine cannot find the FreeType font library. To enable Wine to\n"
3686 "use TrueType fonts please install a version of FreeType greater than\n"
3687 "or equal to 2.0.5.\n"
3688 "http://www.freetype.org\n");
3692 #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;}
3694 LOAD_FUNCPTR(FT_Done_Face
)
3695 LOAD_FUNCPTR(FT_Get_Char_Index
)
3696 LOAD_FUNCPTR(FT_Get_First_Char
)
3697 LOAD_FUNCPTR(FT_Get_Module
)
3698 LOAD_FUNCPTR(FT_Get_Next_Char
)
3699 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3700 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3701 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3702 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3703 LOAD_FUNCPTR(FT_Init_FreeType
)
3704 LOAD_FUNCPTR(FT_Library_Version
)
3705 LOAD_FUNCPTR(FT_Load_Glyph
)
3706 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3707 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3708 #ifndef FT_MULFIX_INLINED
3709 LOAD_FUNCPTR(FT_MulFix
)
3711 LOAD_FUNCPTR(FT_New_Face
)
3712 LOAD_FUNCPTR(FT_New_Memory_Face
)
3713 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3714 LOAD_FUNCPTR(FT_Outline_Transform
)
3715 LOAD_FUNCPTR(FT_Outline_Translate
)
3716 LOAD_FUNCPTR(FT_Render_Glyph
)
3717 LOAD_FUNCPTR(FT_Select_Charmap
)
3718 LOAD_FUNCPTR(FT_Set_Charmap
)
3719 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3720 LOAD_FUNCPTR(FT_Vector_Transform
)
3721 LOAD_FUNCPTR(FT_Vector_Unit
)
3723 /* Don't warn if these ones are missing */
3724 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3725 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3726 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3729 if(pFT_Init_FreeType(&library
) != 0) {
3730 ERR("Can't init FreeType library\n");
3731 wine_dlclose(ft_handle
, NULL
, 0);
3735 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3737 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3738 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3739 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3740 ((FT_Version
.patch
) & 0x0000ff);
3742 font_driver
= &freetype_funcs
;
3747 "Wine cannot find certain functions that it needs inside the FreeType\n"
3748 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3749 "FreeType to at least version 2.1.4.\n"
3750 "http://www.freetype.org\n");
3751 wine_dlclose(ft_handle
, NULL
, 0);
3756 static void init_font_list(void)
3758 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3759 static const WCHAR pathW
[] = {'P','a','t','h',0};
3761 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3762 WCHAR windowsdir
[MAX_PATH
];
3764 const char *data_dir
;
3766 delete_external_font_keys();
3768 /* load the system bitmap fonts */
3769 load_system_fonts();
3771 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3772 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3773 strcatW(windowsdir
, fontsW
);
3774 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3776 ReadFontDir(unixname
, FALSE
);
3777 HeapFree(GetProcessHeap(), 0, unixname
);
3780 /* load the system truetype fonts */
3781 data_dir
= wine_get_data_dir();
3782 if (!data_dir
) data_dir
= wine_get_build_dir();
3783 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3785 strcpy(unixname
, data_dir
);
3786 strcat(unixname
, "/fonts/");
3787 ReadFontDir(unixname
, TRUE
);
3788 HeapFree(GetProcessHeap(), 0, unixname
);
3791 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3792 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3793 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3795 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3796 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3797 &hkey
) == ERROR_SUCCESS
)
3799 LPWSTR data
, valueW
;
3800 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3801 &valuelen
, &datalen
, NULL
, NULL
);
3803 valuelen
++; /* returned value doesn't include room for '\0' */
3804 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3805 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3808 dlen
= datalen
* sizeof(WCHAR
);
3810 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3811 &dlen
) == ERROR_SUCCESS
)
3813 if(data
[0] && (data
[1] == ':'))
3815 if((unixname
= wine_get_unix_file_name(data
)))
3817 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3818 HeapFree(GetProcessHeap(), 0, unixname
);
3821 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
3823 WCHAR pathW
[MAX_PATH
];
3824 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
3827 sprintfW(pathW
, fmtW
, windowsdir
, data
);
3828 if((unixname
= wine_get_unix_file_name(pathW
)))
3830 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3831 HeapFree(GetProcessHeap(), 0, unixname
);
3834 load_font_from_data_dir(data
);
3836 /* reset dlen and vlen */
3841 HeapFree(GetProcessHeap(), 0, data
);
3842 HeapFree(GetProcessHeap(), 0, valueW
);
3846 #ifdef SONAME_LIBFONTCONFIG
3847 load_fontconfig_fonts();
3848 #elif defined(HAVE_CARBON_CARBON_H)
3852 /* then look in any directories that we've specified in the config file */
3853 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3854 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
3860 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
3862 len
+= sizeof(WCHAR
);
3863 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
3864 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
3866 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
3867 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
3868 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
3869 TRACE( "got font path %s\n", debugstr_a(valueA
) );
3874 LPSTR next
= strchr( ptr
, ':' );
3875 if (next
) *next
++ = 0;
3876 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
3877 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
3879 strcpy( unixname
, home
);
3880 strcat( unixname
, ptr
+ 1 );
3881 ReadFontDir( unixname
, TRUE
);
3882 HeapFree( GetProcessHeap(), 0, unixname
);
3885 ReadFontDir( ptr
, TRUE
);
3888 HeapFree( GetProcessHeap(), 0, valueA
);
3890 HeapFree( GetProcessHeap(), 0, valueW
);
3896 static BOOL
move_to_front(const WCHAR
*name
)
3898 Family
*family
, *cursor2
;
3899 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
3901 if(!strcmpiW(family
->FamilyName
, name
))
3903 list_remove(&family
->entry
);
3904 list_add_head(&font_list
, &family
->entry
);
3911 static BOOL
set_default(const WCHAR
**name_list
)
3915 if (move_to_front(*name_list
)) return TRUE
;
3922 static void reorder_font_list(void)
3924 set_default( default_serif_list
);
3925 set_default( default_fixed_list
);
3926 set_default( default_sans_list
);
3929 /*************************************************************
3932 * Initialize FreeType library and create a list of available faces
3934 BOOL
WineEngInit(void)
3939 /* update locale dependent font info in registry */
3942 if(!init_freetype()) return FALSE
;
3944 #ifdef SONAME_LIBFONTCONFIG
3948 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
3950 ERR("Failed to create font mutex\n");
3953 WaitForSingleObject(font_mutex
, INFINITE
);
3955 create_font_cache_key(&hkey_font_cache
, &disposition
);
3957 if(disposition
== REG_CREATED_NEW_KEY
)
3960 load_font_list_from_cache(hkey_font_cache
);
3962 reorder_font_list();
3969 if(disposition
== REG_CREATED_NEW_KEY
)
3970 update_reg_entries();
3972 init_system_links();
3974 ReleaseMutex(font_mutex
);
3979 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
3982 TT_HoriHeader
*pHori
;
3986 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3987 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3989 if(height
== 0) height
= 16;
3991 /* Calc. height of EM square:
3993 * For +ve lfHeight we have
3994 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3995 * Re-arranging gives:
3996 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3998 * For -ve lfHeight we have
4000 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4001 * with il = winAscent + winDescent - units_per_em]
4006 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
4007 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4008 pHori
->Ascender
- pHori
->Descender
);
4010 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4011 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
4019 static struct font_mapping
*map_font_file( const char *name
)
4021 struct font_mapping
*mapping
;
4025 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4026 if (fstat( fd
, &st
) == -1) goto error
;
4028 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4030 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4032 mapping
->refcount
++;
4037 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4040 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4043 if (mapping
->data
== MAP_FAILED
)
4045 HeapFree( GetProcessHeap(), 0, mapping
);
4048 mapping
->refcount
= 1;
4049 mapping
->dev
= st
.st_dev
;
4050 mapping
->ino
= st
.st_ino
;
4051 mapping
->size
= st
.st_size
;
4052 list_add_tail( &mappings_list
, &mapping
->entry
);
4060 static void unmap_font_file( struct font_mapping
*mapping
)
4062 if (!--mapping
->refcount
)
4064 list_remove( &mapping
->entry
);
4065 munmap( mapping
->data
, mapping
->size
);
4066 HeapFree( GetProcessHeap(), 0, mapping
);
4070 static LONG
load_VDMX(GdiFont
*, LONG
);
4072 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4079 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4083 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4084 font
->mapping
= map_font_file( filename
);
4085 HeapFree( GetProcessHeap(), 0, filename
);
4088 WARN("failed to map %s\n", debugstr_w(face
->file
));
4091 data_ptr
= font
->mapping
->data
;
4092 data_size
= font
->mapping
->size
;
4096 data_ptr
= face
->font_data_ptr
;
4097 data_size
= face
->font_data_size
;
4100 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4102 ERR("FT_New_Face rets %d\n", err
);
4106 /* set it here, as load_VDMX needs it */
4107 font
->ft_face
= ft_face
;
4109 if(FT_IS_SCALABLE(ft_face
)) {
4110 /* load the VDMX table if we have one */
4111 font
->ppem
= load_VDMX(font
, height
);
4113 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4114 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4116 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4117 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4119 font
->ppem
= height
;
4120 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4121 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4127 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4129 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4130 a single face with the requested charset. The idea is to check if
4131 the selected font supports the current ANSI codepage, if it does
4132 return the corresponding charset, else return the first charset */
4135 int acp
= GetACP(), i
;
4139 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4141 const SYSTEM_LINKS
*font_link
;
4143 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4144 return csi
.ciCharset
;
4146 font_link
= find_font_link(family_name
);
4147 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4148 return csi
.ciCharset
;
4151 for(i
= 0; i
< 32; i
++) {
4153 if(face
->fs
.fsCsb
[0] & fs0
) {
4154 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4156 return csi
.ciCharset
;
4159 FIXME("TCI failing on %x\n", fs0
);
4163 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4164 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4166 return DEFAULT_CHARSET
;
4169 static GdiFont
*alloc_font(void)
4171 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4174 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4175 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4177 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4178 ret
->total_kern_pairs
= (DWORD
)-1;
4179 ret
->kern_pairs
= NULL
;
4180 list_init(&ret
->child_fonts
);
4184 static void free_font(GdiFont
*font
)
4186 CHILD_FONT
*child
, *child_next
;
4189 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4191 list_remove(&child
->entry
);
4193 free_font(child
->font
);
4194 release_face( child
->face
);
4195 HeapFree(GetProcessHeap(), 0, child
);
4198 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4199 if (font
->mapping
) unmap_font_file( font
->mapping
);
4200 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4201 HeapFree(GetProcessHeap(), 0, font
->potm
);
4202 HeapFree(GetProcessHeap(), 0, font
->name
);
4203 for (i
= 0; i
< font
->gmsize
; i
++)
4204 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4205 HeapFree(GetProcessHeap(), 0, font
->gm
);
4206 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4207 HeapFree(GetProcessHeap(), 0, font
);
4211 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4213 FT_Face ft_face
= font
->ft_face
;
4217 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4224 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4226 /* make sure value of len is the value freetype says it needs */
4229 FT_ULong needed
= 0;
4230 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4231 if( !err
&& needed
< len
) len
= needed
;
4233 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4236 TRACE("Can't find table %c%c%c%c\n",
4237 /* bytes were reversed */
4238 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4239 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4245 /*************************************************************
4248 * load the vdmx entry for the specified height
4251 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4252 ( ( (FT_ULong)_x4 << 24 ) | \
4253 ( (FT_ULong)_x3 << 16 ) | \
4254 ( (FT_ULong)_x2 << 8 ) | \
4257 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4272 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4276 BYTE devXRatio
, devYRatio
;
4277 USHORT numRecs
, numRatios
;
4278 DWORD result
, offset
= -1;
4282 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4284 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4287 /* FIXME: need the real device aspect ratio */
4291 numRecs
= GET_BE_WORD(hdr
[1]);
4292 numRatios
= GET_BE_WORD(hdr
[2]);
4294 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4295 for(i
= 0; i
< numRatios
; i
++) {
4298 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4299 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4302 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4304 if((ratio
.xRatio
== 0 &&
4305 ratio
.yStartRatio
== 0 &&
4306 ratio
.yEndRatio
== 0) ||
4307 (devXRatio
== ratio
.xRatio
&&
4308 devYRatio
>= ratio
.yStartRatio
&&
4309 devYRatio
<= ratio
.yEndRatio
))
4311 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4312 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4313 offset
= GET_BE_WORD(tmp
);
4319 FIXME("No suitable ratio found\n");
4323 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4325 BYTE startsz
, endsz
;
4328 recs
= GET_BE_WORD(group
.recs
);
4329 startsz
= group
.startsz
;
4330 endsz
= group
.endsz
;
4332 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4334 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4335 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4336 if(result
== GDI_ERROR
) {
4337 FIXME("Failed to retrieve vTable\n");
4342 for(i
= 0; i
< recs
; i
++) {
4343 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4344 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4345 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4347 if(yMax
+ -yMin
== height
) {
4350 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4353 if(yMax
+ -yMin
> height
) {
4356 goto end
; /* failed */
4358 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4359 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4360 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4361 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4367 TRACE("ppem not found for height %d\n", height
);
4371 HeapFree(GetProcessHeap(), 0, vTable
);
4377 static void dump_gdi_font_list(void)
4381 TRACE("---------- Font Cache ----------\n");
4382 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4383 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4384 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4387 static void grab_font( GdiFont
*font
)
4389 if (!font
->refcount
++)
4391 list_remove( &font
->unused_entry
);
4392 unused_font_count
--;
4396 static void release_font( GdiFont
*font
)
4399 if (!--font
->refcount
)
4401 TRACE( "font %p\n", font
);
4403 /* add it to the unused list */
4404 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4405 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4407 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4408 TRACE( "freeing %p\n", font
);
4409 list_remove( &font
->entry
);
4410 list_remove( &font
->unused_entry
);
4413 else unused_font_count
++;
4415 if (TRACE_ON(font
)) dump_gdi_font_list();
4419 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4421 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4422 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4423 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4424 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4425 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4428 static void calc_hash(FONT_DESC
*pfd
)
4430 DWORD hash
= 0, *ptr
, two_chars
;
4434 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4436 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4438 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4440 pwc
= (WCHAR
*)&two_chars
;
4442 *pwc
= toupperW(*pwc
);
4444 *pwc
= toupperW(*pwc
);
4448 hash
^= !pfd
->can_use_bitmap
;
4453 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4460 fd
.can_use_bitmap
= can_use_bitmap
;
4463 /* try the in-use list */
4464 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4466 if(fontcmp(ret
, &fd
)) continue;
4467 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4468 list_remove( &ret
->entry
);
4469 list_add_head( &gdi_font_list
, &ret
->entry
);
4476 static void add_to_cache(GdiFont
*font
)
4478 static DWORD cache_num
= 1;
4480 font
->cache_num
= cache_num
++;
4481 list_add_head(&gdi_font_list
, &font
->entry
);
4482 TRACE( "font %p\n", font
);
4485 /*************************************************************
4486 * create_child_font_list
4488 static BOOL
create_child_font_list(GdiFont
*font
)
4491 SYSTEM_LINKS
*font_link
;
4492 CHILD_FONT
*font_link_entry
, *new_child
;
4496 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4497 font_name
= psub
? psub
->to
.name
: font
->name
;
4498 font_link
= find_font_link(font_name
);
4499 if (font_link
!= NULL
)
4501 TRACE("found entry in system list\n");
4502 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4504 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4505 new_child
->face
= font_link_entry
->face
;
4506 new_child
->font
= NULL
;
4507 new_child
->face
->refcount
++;
4508 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4509 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4514 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4515 * Sans Serif. This is how asian windows get default fallbacks for fonts
4517 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4518 font
->charset
!= OEM_CHARSET
&&
4519 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4521 font_link
= find_font_link(szDefaultFallbackLink
);
4522 if (font_link
!= NULL
)
4524 TRACE("found entry in default fallback list\n");
4525 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4527 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4528 new_child
->face
= font_link_entry
->face
;
4529 new_child
->font
= NULL
;
4530 new_child
->face
->refcount
++;
4531 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4532 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4541 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4543 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4545 if (pFT_Set_Charmap
)
4548 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4550 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4552 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4554 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4556 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4557 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4559 switch (ft_face
->charmaps
[i
]->platform_id
)
4562 cmap_def
= ft_face
->charmaps
[i
];
4564 case 0: /* Apple Unicode */
4565 cmap0
= ft_face
->charmaps
[i
];
4567 case 1: /* Macintosh */
4568 cmap1
= ft_face
->charmaps
[i
];
4571 cmap2
= ft_face
->charmaps
[i
];
4573 case 3: /* Microsoft */
4574 cmap3
= ft_face
->charmaps
[i
];
4579 if (cmap3
) /* prefer Microsoft cmap table */
4580 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4582 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4584 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4586 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4588 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4590 return ft_err
== FT_Err_Ok
;
4593 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4597 /*************************************************************
4600 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4601 LPCWSTR output
, const DEVMODEW
*devmode
)
4603 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4605 if (!physdev
) return FALSE
;
4606 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4611 /*************************************************************
4614 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4616 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4617 release_font( physdev
->font
);
4618 HeapFree( GetProcessHeap(), 0, physdev
);
4622 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4624 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4625 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4626 const FT_Encoding
*encs
= regular_order
;
4628 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4632 if (select_charmap( face
, *encs
)) break;
4638 #define GASP_GRIDFIT 0x01
4639 #define GASP_DOGRAY 0x02
4640 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4642 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4645 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4646 WORD
*alloced
= NULL
, *ptr
= buf
;
4647 WORD num_recs
, version
;
4651 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4652 if (size
== GDI_ERROR
) return FALSE
;
4653 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4654 if (size
> sizeof(buf
))
4656 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4657 if (!ptr
) return FALSE
;
4660 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4662 version
= GET_BE_WORD( *ptr
++ );
4663 num_recs
= GET_BE_WORD( *ptr
++ );
4665 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4667 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4673 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4674 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4677 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4681 HeapFree( GetProcessHeap(), 0, alloced
);
4685 /*************************************************************
4686 * freetype_SelectFont
4688 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
4690 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4692 Face
*face
, *best
, *best_bitmap
;
4693 Family
*family
, *last_resort_family
;
4694 const struct list
*face_list
;
4695 INT height
, width
= 0;
4696 unsigned int score
= 0, new_score
;
4697 signed int diff
= 0, newdiff
;
4698 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
4702 FontSubst
*psub
= NULL
;
4703 DC
*dc
= get_dc_ptr( dev
->hdc
);
4704 const SYSTEM_LINKS
*font_link
;
4706 if (!hfont
) /* notification that the font has been changed by another driver */
4708 release_font( physdev
->font
);
4709 physdev
->font
= NULL
;
4710 release_dc_ptr( dc
);
4714 GetObjectW( hfont
, sizeof(lf
), &lf
);
4715 lf
.lfWidth
= abs(lf
.lfWidth
);
4717 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
4719 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4720 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
4721 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
4724 if(dc
->GraphicsMode
== GM_ADVANCED
)
4726 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
4727 /* Try to avoid not necessary glyph transformations */
4728 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
4730 lf
.lfHeight
*= fabs(dcmat
.eM11
);
4731 lf
.lfWidth
*= fabs(dcmat
.eM11
);
4732 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
4737 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4738 font scaling abilities. */
4739 dcmat
.eM11
= dcmat
.eM22
= 1.0;
4740 dcmat
.eM21
= dcmat
.eM12
= 0;
4741 lf
.lfOrientation
= lf
.lfEscapement
;
4742 if (dc
->vport2WorldValid
)
4744 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
4745 lf
.lfOrientation
= -lf
.lfOrientation
;
4746 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
4747 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
4751 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
4752 dcmat
.eM21
, dcmat
.eM22
);
4755 EnterCriticalSection( &freetype_cs
);
4757 /* check the cache first */
4758 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
4759 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
4763 TRACE("not in cache\n");
4766 ret
->font_desc
.matrix
= dcmat
;
4767 ret
->font_desc
.lf
= lf
;
4768 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
4769 calc_hash(&ret
->font_desc
);
4771 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4772 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4773 original value lfCharSet. Note this is a special case for
4774 Symbol and doesn't happen at least for "Wingdings*" */
4776 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
4777 lf
.lfCharSet
= SYMBOL_CHARSET
;
4779 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
4780 switch(lf
.lfCharSet
) {
4781 case DEFAULT_CHARSET
:
4782 csi
.fs
.fsCsb
[0] = 0;
4785 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
4786 csi
.fs
.fsCsb
[0] = 0;
4792 if(lf
.lfFaceName
[0] != '\0') {
4793 CHILD_FONT
*font_link_entry
;
4794 LPWSTR FaceName
= lf
.lfFaceName
;
4796 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
4799 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
4800 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
4801 if (psub
->to
.charset
!= -1)
4802 lf
.lfCharSet
= psub
->to
.charset
;
4805 /* We want a match on name and charset or just name if
4806 charset was DEFAULT_CHARSET. If the latter then
4807 we fixup the returned charset later in get_nearest_charset
4808 where we'll either use the charset of the current ansi codepage
4809 or if that's unavailable the first charset that the font supports.
4811 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4812 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
4813 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
4815 font_link
= find_font_link(family
->FamilyName
);
4816 face_list
= get_face_list_from_family(family
);
4817 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4818 if (!(face
->scalable
|| can_use_bitmap
))
4820 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4822 if (font_link
!= NULL
&&
4823 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4825 if (!csi
.fs
.fsCsb
[0])
4831 /* Search by full face name. */
4832 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4833 face_list
= get_face_list_from_family(family
);
4834 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4835 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
4836 (face
->scalable
|| can_use_bitmap
))
4838 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4840 font_link
= find_font_link(family
->FamilyName
);
4841 if (font_link
!= NULL
&&
4842 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4849 * Try check the SystemLink list first for a replacement font.
4850 * We may find good replacements there.
4852 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
4854 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
4855 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
4857 TRACE("found entry in system list\n");
4858 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4860 const SYSTEM_LINKS
*links
;
4862 face
= font_link_entry
->face
;
4863 if (!(face
->scalable
|| can_use_bitmap
))
4865 family
= face
->family
;
4866 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
4868 links
= find_font_link(family
->FamilyName
);
4869 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
4876 psub
= NULL
; /* substitution is no more relevant */
4878 /* If requested charset was DEFAULT_CHARSET then try using charset
4879 corresponding to the current ansi codepage */
4880 if (!csi
.fs
.fsCsb
[0])
4883 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
4884 FIXME("TCI failed on codepage %d\n", acp
);
4885 csi
.fs
.fsCsb
[0] = 0;
4887 lf
.lfCharSet
= csi
.ciCharset
;
4890 want_vertical
= (lf
.lfFaceName
[0] == '@');
4892 /* Face families are in the top 4 bits of lfPitchAndFamily,
4893 so mask with 0xF0 before testing */
4895 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
4896 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
4897 strcpyW(lf
.lfFaceName
, defFixed
);
4898 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
4899 strcpyW(lf
.lfFaceName
, defSerif
);
4900 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
4901 strcpyW(lf
.lfFaceName
, defSans
);
4903 strcpyW(lf
.lfFaceName
, defSans
);
4904 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4905 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
4906 font_link
= find_font_link(family
->FamilyName
);
4907 face_list
= get_face_list_from_family(family
);
4908 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4909 if (!(face
->scalable
|| can_use_bitmap
))
4911 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4913 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4919 last_resort_family
= NULL
;
4920 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4921 font_link
= find_font_link(family
->FamilyName
);
4922 face_list
= get_face_list_from_family(family
);
4923 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4924 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
4925 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4926 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
4929 if(can_use_bitmap
&& !last_resort_family
)
4930 last_resort_family
= family
;
4935 if(last_resort_family
) {
4936 family
= last_resort_family
;
4937 csi
.fs
.fsCsb
[0] = 0;
4941 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
4942 face_list
= get_face_list_from_family(family
);
4943 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
4944 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
4945 csi
.fs
.fsCsb
[0] = 0;
4946 WARN("just using first face for now\n");
4949 if(can_use_bitmap
&& !last_resort_family
)
4950 last_resort_family
= family
;
4953 if(!last_resort_family
) {
4954 FIXME("can't find a single appropriate font - bailing\n");
4960 WARN("could only find a bitmap font - this will probably look awful!\n");
4961 family
= last_resort_family
;
4962 csi
.fs
.fsCsb
[0] = 0;
4965 it
= lf
.lfItalic
? 1 : 0;
4966 bd
= lf
.lfWeight
> 550 ? 1 : 0;
4968 height
= lf
.lfHeight
;
4970 face
= best
= best_bitmap
= NULL
;
4971 font_link
= find_font_link(family
->FamilyName
);
4972 face_list
= get_face_list_from_family(family
);
4973 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
4975 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
4976 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
4981 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
4982 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
4983 new_score
= (italic
^ it
) + (bold
^ bd
);
4984 if(!best
|| new_score
<= score
)
4986 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4987 italic
, bold
, it
, bd
);
4990 if(best
->scalable
&& score
== 0) break;
4994 newdiff
= height
- (signed int)(best
->size
.height
);
4996 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
4997 if(!best_bitmap
|| new_score
< score
||
4998 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5000 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5003 if(score
== 0 && diff
== 0) break;
5010 face
= best
->scalable
? best
: best_bitmap
;
5011 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5012 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5015 height
= lf
.lfHeight
;
5019 if(csi
.fs
.fsCsb
[0]) {
5020 ret
->charset
= lf
.lfCharSet
;
5021 ret
->codepage
= csi
.ciACP
;
5024 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5026 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5027 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5029 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5031 if(!face
->scalable
) {
5032 /* Windows uses integer scaling factors for bitmap fonts */
5033 INT scale
, scaled_height
;
5034 GdiFont
*cachedfont
;
5036 /* FIXME: rotation of bitmap fonts is ignored */
5037 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5039 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5040 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5041 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5042 /* As we changed the matrix, we need to search the cache for the font again,
5043 * otherwise we might explode the cache. */
5044 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5045 TRACE("Found cached font after non-scalable matrix rescale!\n");
5050 calc_hash(&ret
->font_desc
);
5052 if (height
!= 0) height
= diff
;
5053 height
+= face
->size
.height
;
5055 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5056 scaled_height
= scale
* face
->size
.height
;
5057 /* Only jump to the next height if the difference <= 25% original height */
5058 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5059 /* The jump between unscaled and doubled is delayed by 1 */
5060 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5061 ret
->scale_y
= scale
;
5063 width
= face
->size
.x_ppem
>> 6;
5064 height
= face
->size
.y_ppem
>> 6;
5068 TRACE("font scale y: %f\n", ret
->scale_y
);
5070 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5079 ret
->ntmFlags
= face
->ntmFlags
;
5081 pick_charmap( ret
->ft_face
, ret
->charset
);
5083 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5084 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5085 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5086 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5087 create_child_font_list(ret
);
5089 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5091 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5092 if (length
!= GDI_ERROR
)
5094 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5095 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5096 TRACE("Loaded GSUB table of %i bytes\n",length
);
5099 ret
->aa_flags
= HIWORD( face
->flags
);
5101 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5107 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5109 switch (lf
.lfQuality
)
5111 case NONANTIALIASED_QUALITY
:
5112 case ANTIALIASED_QUALITY
:
5113 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5115 case CLEARTYPE_QUALITY
:
5116 case CLEARTYPE_NATURAL_QUALITY
:
5118 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5119 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5121 /* fixup the antialiasing flags for that font */
5124 case WINE_GGO_HRGB_BITMAP
:
5125 case WINE_GGO_HBGR_BITMAP
:
5126 case WINE_GGO_VRGB_BITMAP
:
5127 case WINE_GGO_VBGR_BITMAP
:
5128 if (is_subpixel_rendering_enabled()) break;
5129 *aa_flags
= GGO_GRAY4_BITMAP
;
5131 case GGO_GRAY2_BITMAP
:
5132 case GGO_GRAY4_BITMAP
:
5133 case GGO_GRAY8_BITMAP
:
5134 case WINE_GGO_GRAY16_BITMAP
:
5135 if (is_hinting_enabled())
5138 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5140 TRACE( "font %s %d aa disabled by GASP\n",
5141 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5142 *aa_flags
= GGO_BITMAP
;
5147 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5148 release_font( physdev
->font
);
5149 physdev
->font
= ret
;
5151 LeaveCriticalSection( &freetype_cs
);
5152 release_dc_ptr( dc
);
5153 return ret
? hfont
: 0;
5156 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5163 id
+= IDS_FIRST_SCRIPT
;
5164 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5165 if (!rsrc
) return 0;
5166 hMem
= LoadResource( gdi32_module
, rsrc
);
5167 if (!hMem
) return 0;
5169 p
= LockResource( hMem
);
5171 while (id
--) p
+= *p
+ 1;
5173 i
= min(LF_FACESIZE
- 1, *p
);
5174 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5180 /***************************************************
5181 * create_enum_charset_list
5183 * This function creates charset enumeration list because in DEFAULT_CHARSET
5184 * case, the ANSI codepage's charset takes precedence over other charsets.
5185 * This function works as a filter other than DEFAULT_CHARSET case.
5187 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5192 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5193 csi
.fs
.fsCsb
[0] != 0) {
5194 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5195 list
->element
[n
].charset
= csi
.ciCharset
;
5196 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5199 else { /* charset is DEFAULT_CHARSET or invalid. */
5203 /* Set the current codepage's charset as the first element. */
5205 if (TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5206 csi
.fs
.fsCsb
[0] != 0) {
5207 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5208 list
->element
[n
].charset
= csi
.ciCharset
;
5209 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5210 mask
|= csi
.fs
.fsCsb
[0];
5214 /* Fill out left elements. */
5215 for (i
= 0; i
< 32; i
++) {
5217 fs
.fsCsb
[0] = 1L << i
;
5219 if (fs
.fsCsb
[0] & mask
)
5220 continue; /* skip, already added. */
5221 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5222 continue; /* skip, this is an invalid fsCsb bit. */
5224 list
->element
[n
].mask
= fs
.fsCsb
[0];
5225 list
->element
[n
].charset
= csi
.ciCharset
;
5226 load_script_name( i
, list
->element
[n
].name
);
5227 mask
|= fs
.fsCsb
[0];
5231 /* add catch all mask for remaining bits */
5234 list
->element
[n
].mask
= ~mask
;
5235 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5236 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5245 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5246 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5251 if (face
->cached_enum_data
)
5254 *pelf
= face
->cached_enum_data
->elf
;
5255 *pntm
= face
->cached_enum_data
->ntm
;
5256 *ptype
= face
->cached_enum_data
->type
;
5260 font
= alloc_font();
5262 if(face
->scalable
) {
5266 height
= face
->size
.y_ppem
>> 6;
5267 width
= face
->size
.x_ppem
>> 6;
5269 font
->scale_y
= 1.0;
5271 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5277 font
->name
= strdupW( family_name
);
5278 font
->ntmFlags
= face
->ntmFlags
;
5280 if (get_outline_text_metrics(font
))
5282 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5284 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5285 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5286 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5288 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5289 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5291 lstrcpynW(pelf
->elfFullName
,
5292 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5294 lstrcpynW(pelf
->elfStyle
,
5295 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5300 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5302 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5303 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5304 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5306 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5308 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5310 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5311 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5314 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5315 pntm
->ntmFontSig
= face
->fs
;
5317 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5319 pelf
->elfLogFont
.lfEscapement
= 0;
5320 pelf
->elfLogFont
.lfOrientation
= 0;
5321 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5322 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5323 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5324 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5325 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5326 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5327 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5328 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5329 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5330 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5331 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5334 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5335 *ptype
|= TRUETYPE_FONTTYPE
;
5336 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5337 *ptype
|= DEVICE_FONTTYPE
;
5338 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5339 *ptype
|= RASTER_FONTTYPE
;
5341 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5342 if (face
->cached_enum_data
)
5344 face
->cached_enum_data
->elf
= *pelf
;
5345 face
->cached_enum_data
->ntm
= *pntm
;
5346 face
->cached_enum_data
->type
= *ptype
;
5352 static BOOL
family_matches(Family
*family
, const LOGFONTW
*lf
)
5355 const struct list
*face_list
;
5357 if (!strcmpiW(lf
->lfFaceName
, family
->FamilyName
)) return TRUE
;
5359 face_list
= get_face_list_from_family(family
);
5360 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5361 if (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
)) return TRUE
;
5366 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const LOGFONTW
*lf
)
5368 if (!strcmpiW(lf
->lfFaceName
, family_name
)) return TRUE
;
5370 return (face
->FullName
&& !strcmpiW(lf
->lfFaceName
, face
->FullName
));
5373 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5374 FONTENUMPROCW proc
, LPARAM lparam
)
5377 NEWTEXTMETRICEXW ntm
;
5381 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5382 for(i
= 0; i
< list
->total
; i
++) {
5383 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5384 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5385 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5386 i
= list
->total
; /* break out of loop after enumeration */
5390 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5391 /* use the DEFAULT_CHARSET case only if no other charset is present */
5392 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5393 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5394 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5395 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5396 if (!elf
.elfScript
[0])
5397 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5399 /* Font Replacement */
5400 if (family
!= face
->family
)
5402 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5404 strcpyW(elf
.elfFullName
, face
->FullName
);
5406 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5408 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5409 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5410 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5411 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5412 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5413 ntm
.ntmTm
.ntmFlags
);
5414 /* release section before callback (FIXME) */
5415 LeaveCriticalSection( &freetype_cs
);
5416 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5417 EnterCriticalSection( &freetype_cs
);
5422 /*************************************************************
5423 * freetype_EnumFonts
5425 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5429 const struct list
*face_list
;
5431 struct enum_charset_list enum_charsets
;
5435 lf
.lfCharSet
= DEFAULT_CHARSET
;
5436 lf
.lfPitchAndFamily
= 0;
5437 lf
.lfFaceName
[0] = 0;
5441 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5443 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5446 EnterCriticalSection( &freetype_cs
);
5447 if(plf
->lfFaceName
[0]) {
5449 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5452 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5453 debugstr_w(psub
->to
.name
));
5455 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
5459 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5460 if (!family_matches(family
, plf
)) continue;
5461 face_list
= get_face_list_from_family(family
);
5462 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5463 if (!face_matches(family
->FamilyName
, face
, plf
)) continue;
5464 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5468 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5469 face_list
= get_face_list_from_family(family
);
5470 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5471 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5474 LeaveCriticalSection( &freetype_cs
);
5478 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5480 pt
->x
.value
= vec
->x
>> 6;
5481 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5482 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5483 pt
->y
.value
= vec
->y
>> 6;
5484 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5485 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5489 /***************************************************
5490 * According to the MSDN documentation on WideCharToMultiByte,
5491 * certain codepages cannot set the default_used parameter.
5492 * This returns TRUE if the codepage can set that parameter, false else
5493 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5495 static BOOL
codepage_sets_default_used(UINT codepage
)
5509 * GSUB Table handling functions
5512 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5514 const GSUB_CoverageFormat1
* cf1
;
5518 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5520 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5522 TRACE("Coverage Format 1, %i glyphs\n",count
);
5523 for (i
= 0; i
< count
; i
++)
5524 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5528 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5530 const GSUB_CoverageFormat2
* cf2
;
5533 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5535 count
= GET_BE_WORD(cf2
->RangeCount
);
5536 TRACE("Coverage Format 2, %i ranges\n",count
);
5537 for (i
= 0; i
< count
; i
++)
5539 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5541 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5542 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5544 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5545 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5551 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5556 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
5558 const GSUB_ScriptList
*script
;
5559 const GSUB_Script
*deflt
= NULL
;
5561 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
5563 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
5564 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
5566 const GSUB_Script
*scr
;
5569 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
5570 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
5572 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
5574 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
5580 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
5584 const GSUB_LangSys
*Lang
;
5586 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
5588 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
5590 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
5591 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5593 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
5596 offset
= GET_BE_WORD(script
->DefaultLangSys
);
5599 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
5605 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
5608 const GSUB_FeatureList
*feature
;
5609 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
5611 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
5612 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
5614 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5615 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5617 const GSUB_Feature
*feat
;
5618 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5625 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5629 const GSUB_LookupList
*lookup
;
5630 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5632 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5633 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5635 const GSUB_LookupTable
*look
;
5636 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5637 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5638 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5639 if (GET_BE_WORD(look
->LookupType
) != 1)
5640 FIXME("We only handle SubType 1\n");
5645 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5647 const GSUB_SingleSubstFormat1
*ssf1
;
5648 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5649 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5650 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5652 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5653 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5654 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5656 TRACE(" Glyph 0x%x ->",glyph
);
5657 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5658 TRACE(" 0x%x\n",glyph
);
5663 const GSUB_SingleSubstFormat2
*ssf2
;
5667 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5668 offset
= GET_BE_WORD(ssf1
->Coverage
);
5669 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5670 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5671 TRACE(" Coverage index %i\n",index
);
5674 TRACE(" Glyph is 0x%x ->",glyph
);
5675 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5676 TRACE("0x%x\n",glyph
);
5685 static const char* get_opentype_script(const GdiFont
*font
)
5688 * I am not sure if this is the correct way to generate our script tag
5691 switch (font
->charset
)
5693 case ANSI_CHARSET
: return "latn";
5694 case BALTIC_CHARSET
: return "latn"; /* ?? */
5695 case CHINESEBIG5_CHARSET
: return "hani";
5696 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5697 case GB2312_CHARSET
: return "hani";
5698 case GREEK_CHARSET
: return "grek";
5699 case HANGUL_CHARSET
: return "hang";
5700 case RUSSIAN_CHARSET
: return "cyrl";
5701 case SHIFTJIS_CHARSET
: return "kana";
5702 case TURKISH_CHARSET
: return "latn"; /* ?? */
5703 case VIETNAMESE_CHARSET
: return "latn";
5704 case JOHAB_CHARSET
: return "latn"; /* ?? */
5705 case ARABIC_CHARSET
: return "arab";
5706 case HEBREW_CHARSET
: return "hebr";
5707 case THAI_CHARSET
: return "thai";
5708 default: return "latn";
5712 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5714 const GSUB_Header
*header
;
5715 const GSUB_Script
*script
;
5716 const GSUB_LangSys
*language
;
5717 const GSUB_Feature
*feature
;
5719 if (!font
->GSUB_Table
)
5722 header
= font
->GSUB_Table
;
5724 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5727 TRACE("Script not found\n");
5730 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5733 TRACE("Language not found\n");
5736 feature
= GSUB_get_feature(header
, language
, "vrt2");
5738 feature
= GSUB_get_feature(header
, language
, "vert");
5741 TRACE("vrt2/vert feature not found\n");
5744 return GSUB_apply_feature(header
, feature
, glyph
);
5747 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5751 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5752 WCHAR wc
= (WCHAR
)glyph
;
5754 BOOL
*default_used_pointer
;
5757 default_used_pointer
= NULL
;
5758 default_used
= FALSE
;
5759 if (codepage_sets_default_used(font
->codepage
))
5760 default_used_pointer
= &default_used
;
5761 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
5763 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
5764 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
5769 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
5770 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
5774 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
5776 if (glyph
< 0x100) glyph
+= 0xf000;
5777 /* there is a number of old pre-Unicode "broken" TTFs, which
5778 do have symbols at U+00XX instead of U+f0XX */
5779 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
5780 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
5782 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
5787 /*************************************************************
5788 * freetype_GetGlyphIndices
5790 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
5792 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5795 BOOL got_default
= FALSE
;
5799 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
5800 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
5803 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
5805 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
5810 EnterCriticalSection( &freetype_cs
);
5812 for(i
= 0; i
< count
; i
++)
5814 pgi
[i
] = get_glyph_index(physdev
->font
, lpstr
[i
]);
5819 if (FT_IS_SFNT(physdev
->font
->ft_face
))
5821 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(physdev
->font
->ft_face
, ft_sfnt_os2
);
5822 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(physdev
->font
, pOS2
->usDefaultChar
) : 0);
5827 get_text_metrics(physdev
->font
, &textm
);
5828 default_char
= textm
.tmDefaultChar
;
5832 pgi
[i
] = default_char
;
5835 LeaveCriticalSection( &freetype_cs
);
5839 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
5841 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
5842 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
5845 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
5847 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
5848 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
5851 static inline BYTE
get_max_level( UINT format
)
5855 case GGO_GRAY2_BITMAP
: return 4;
5856 case GGO_GRAY4_BITMAP
: return 16;
5857 case GGO_GRAY8_BITMAP
: return 64;
5862 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5864 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
5865 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
5868 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
5869 FT_Face ft_face
= incoming_font
->ft_face
;
5870 GdiFont
*font
= incoming_font
;
5871 FT_UInt glyph_index
;
5872 DWORD width
, height
, pitch
, needed
= 0;
5873 FT_Bitmap ft_bitmap
;
5875 INT left
, right
, top
= 0, bottom
= 0, adv
;
5877 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
5878 double widthRatio
= 1.0;
5879 FT_Matrix transMat
= identityMat
;
5880 FT_Matrix transMatUnrotated
;
5881 BOOL needsTransform
= FALSE
;
5882 BOOL tategaki
= (font
->GSUB_Table
!= NULL
);
5883 UINT original_index
;
5884 LONG avgAdvance
= 0;
5887 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
5888 buflen
, buf
, lpmat
);
5890 TRACE("font transform %f %f %f %f\n",
5891 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
5892 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
5894 if(format
& GGO_GLYPH_INDEX
) {
5895 glyph_index
= get_GSUB_vert_glyph(incoming_font
,glyph
);
5896 original_index
= glyph
;
5897 format
&= ~GGO_GLYPH_INDEX
;
5899 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
5900 ft_face
= font
->ft_face
;
5901 original_index
= glyph_index
;
5904 if(format
& GGO_UNHINTED
) {
5905 load_flags
|= FT_LOAD_NO_HINTING
;
5906 format
&= ~GGO_UNHINTED
;
5909 /* tategaki never appears to happen to lower glyph index */
5910 if (glyph_index
< TATEGAKI_LOWER_BOUND
)
5913 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
5914 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
5915 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
5916 font
->gmsize
* sizeof(GM
*));
5918 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
5919 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
5921 *lpgm
= FONT_GM(font
,original_index
)->gm
;
5922 *abc
= FONT_GM(font
,original_index
)->abc
;
5923 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
5924 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
5925 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
5926 return 1; /* FIXME */
5930 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
5931 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
5933 /* Scaling factor */
5938 get_text_metrics(font
, &tm
);
5940 widthRatio
= (double)font
->aveWidth
;
5941 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
5944 widthRatio
= font
->scale_y
;
5946 /* Scaling transform */
5947 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
5950 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
5953 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
5955 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
5956 needsTransform
= TRUE
;
5959 /* Slant transform */
5960 if (font
->fake_italic
) {
5963 slantMat
.xx
= (1 << 16);
5964 slantMat
.xy
= ((1 << 16) >> 2);
5966 slantMat
.yy
= (1 << 16);
5967 pFT_Matrix_Multiply(&slantMat
, &transMat
);
5968 needsTransform
= TRUE
;
5971 /* Rotation transform */
5972 transMatUnrotated
= transMat
;
5973 if(font
->orientation
&& !tategaki
) {
5974 FT_Matrix rotationMat
;
5976 angle
= FT_FixedFromFloat((double)font
->orientation
/ 10.0);
5977 pFT_Vector_Unit(&vecAngle
, angle
);
5978 rotationMat
.xx
= vecAngle
.x
;
5979 rotationMat
.xy
= -vecAngle
.y
;
5980 rotationMat
.yx
= -rotationMat
.xy
;
5981 rotationMat
.yy
= rotationMat
.xx
;
5983 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
5984 needsTransform
= TRUE
;
5987 /* World transform */
5988 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
5991 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
5992 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
5993 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
5994 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
5995 pFT_Matrix_Multiply(&worldMat
, &transMat
);
5996 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
5997 needsTransform
= TRUE
;
6000 /* Extra transformation specified by caller */
6001 if (!is_identity_MAT2(lpmat
))
6004 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6005 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6006 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6007 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6008 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6009 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6010 needsTransform
= TRUE
;
6013 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6015 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6018 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6022 if(FT_IS_SCALABLE(incoming_font
->ft_face
)) {
6024 if (get_text_metrics(incoming_font
, &tm
) &&
6025 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6026 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6027 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6029 (ft_face
->glyph
->metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6030 TRACE("Fixed-pitch full-width character detected\n");
6032 avgAdvance
= 0; /* cancel this feature */
6036 if(!needsTransform
) {
6037 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
) & -64;
6038 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) + 63) & -64;
6040 adv
= (INT
)(ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
6042 adv
= (INT
)avgAdvance
* 2;
6044 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
6045 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
6046 ft_face
->glyph
->metrics
.height
) & -64;
6047 lpgm
->gmCellIncX
= adv
;
6048 lpgm
->gmCellIncY
= 0;
6055 for(xc
= 0; xc
< 2; xc
++) {
6056 for(yc
= 0; yc
< 2; yc
++) {
6057 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
6058 xc
* ft_face
->glyph
->metrics
.width
);
6059 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
6060 yc
* ft_face
->glyph
->metrics
.height
;
6061 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6062 pFT_Vector_Transform(&vec
, &transMat
);
6063 if(xc
== 0 && yc
== 0) {
6064 left
= right
= vec
.x
;
6065 top
= bottom
= vec
.y
;
6067 if(vec
.x
< left
) left
= vec
.x
;
6068 else if(vec
.x
> right
) right
= vec
.x
;
6069 if(vec
.y
< bottom
) bottom
= vec
.y
;
6070 else if(vec
.y
> top
) top
= vec
.y
;
6075 right
= (right
+ 63) & -64;
6076 bottom
= bottom
& -64;
6077 top
= (top
+ 63) & -64;
6079 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6080 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
6082 pFT_Vector_Transform(&vec
, &transMat
);
6083 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
6084 if (!avgAdvance
|| vec
.y
)
6085 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
6087 vec
.x
= incoming_font
->ntmAvgWidth
;
6089 pFT_Vector_Transform(&vec
, &transMat
);
6090 lpgm
->gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6093 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
6095 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6096 if (!avgAdvance
|| vec
.y
)
6097 adv
= (vec
.x
+63) >> 6;
6099 vec
.x
= incoming_font
->ntmAvgWidth
;
6101 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6102 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6106 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
6107 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
6108 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
6109 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
6110 abc
->abcA
= left
>> 6;
6111 abc
->abcB
= (right
- left
) >> 6;
6112 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6114 TRACE("%u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6115 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6116 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6118 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6119 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6121 FONT_GM(font
,original_index
)->gm
= *lpgm
;
6122 FONT_GM(font
,original_index
)->abc
= *abc
;
6123 FONT_GM(font
,original_index
)->init
= TRUE
;
6126 if(format
== GGO_METRICS
)
6128 return 1; /* FIXME */
6131 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6132 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6134 TRACE("loaded a bitmap\n");
6140 width
= lpgm
->gmBlackBoxX
;
6141 height
= lpgm
->gmBlackBoxY
;
6142 pitch
= ((width
+ 31) >> 5) << 2;
6143 needed
= pitch
* height
;
6145 if(!buf
|| !buflen
) break;
6147 switch(ft_face
->glyph
->format
) {
6148 case ft_glyph_format_bitmap
:
6150 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6151 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6152 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6154 memcpy(dst
, src
, w
);
6155 src
+= ft_face
->glyph
->bitmap
.pitch
;
6161 case ft_glyph_format_outline
:
6162 ft_bitmap
.width
= width
;
6163 ft_bitmap
.rows
= height
;
6164 ft_bitmap
.pitch
= pitch
;
6165 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6166 ft_bitmap
.buffer
= buf
;
6169 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6171 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6173 /* Note: FreeType will only set 'black' bits for us. */
6174 memset(buf
, 0, needed
);
6175 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6179 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6184 case GGO_GRAY2_BITMAP
:
6185 case GGO_GRAY4_BITMAP
:
6186 case GGO_GRAY8_BITMAP
:
6187 case WINE_GGO_GRAY16_BITMAP
:
6189 unsigned int max_level
, row
, col
;
6192 width
= lpgm
->gmBlackBoxX
;
6193 height
= lpgm
->gmBlackBoxY
;
6194 pitch
= (width
+ 3) / 4 * 4;
6195 needed
= pitch
* height
;
6197 if(!buf
|| !buflen
) break;
6199 max_level
= get_max_level( format
);
6201 switch(ft_face
->glyph
->format
) {
6202 case ft_glyph_format_bitmap
:
6204 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6205 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6207 memset( buf
, 0, needed
);
6209 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6210 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6211 src
+= ft_face
->glyph
->bitmap
.pitch
;
6216 case ft_glyph_format_outline
:
6218 ft_bitmap
.width
= width
;
6219 ft_bitmap
.rows
= height
;
6220 ft_bitmap
.pitch
= pitch
;
6221 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6222 ft_bitmap
.buffer
= buf
;
6225 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
6227 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6229 memset(ft_bitmap
.buffer
, 0, buflen
);
6231 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6233 if (max_level
!= 255)
6235 for (row
= 0, start
= buf
; row
< height
; row
++)
6237 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6238 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6246 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6252 case WINE_GGO_HRGB_BITMAP
:
6253 case WINE_GGO_HBGR_BITMAP
:
6254 case WINE_GGO_VRGB_BITMAP
:
6255 case WINE_GGO_VBGR_BITMAP
:
6256 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6258 switch (ft_face
->glyph
->format
)
6260 case FT_GLYPH_FORMAT_BITMAP
:
6265 width
= lpgm
->gmBlackBoxX
;
6266 height
= lpgm
->gmBlackBoxY
;
6268 needed
= pitch
* height
;
6270 if (!buf
|| !buflen
) break;
6272 memset(buf
, 0, buflen
);
6274 src
= ft_face
->glyph
->bitmap
.buffer
;
6275 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6277 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6280 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6282 if ( src
[x
/ 8] & masks
[x
% 8] )
6283 ((unsigned int *)dst
)[x
] = ~0u;
6292 case FT_GLYPH_FORMAT_OUTLINE
:
6296 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6297 INT x_shift
, y_shift
;
6299 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6300 FT_Render_Mode render_mode
=
6301 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6302 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6304 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6306 if ( render_mode
== FT_RENDER_MODE_LCD
)
6308 lpgm
->gmBlackBoxX
+= 2;
6309 lpgm
->gmptGlyphOrigin
.x
-= 1;
6313 lpgm
->gmBlackBoxY
+= 2;
6314 lpgm
->gmptGlyphOrigin
.y
+= 1;
6318 width
= lpgm
->gmBlackBoxX
;
6319 height
= lpgm
->gmBlackBoxY
;
6321 needed
= pitch
* height
;
6323 if (!buf
|| !buflen
) break;
6325 memset(buf
, 0, buflen
);
6327 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6329 if ( needsTransform
)
6330 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMat
);
6332 if ( pFT_Library_SetLcdFilter
)
6333 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6334 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6336 src
= ft_face
->glyph
->bitmap
.buffer
;
6337 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6338 src_width
= ft_face
->glyph
->bitmap
.width
;
6339 src_height
= ft_face
->glyph
->bitmap
.rows
;
6341 if ( render_mode
== FT_RENDER_MODE_LCD
)
6349 rgb_interval
= src_pitch
;
6354 x_shift
= ft_face
->glyph
->bitmap_left
- lpgm
->gmptGlyphOrigin
.x
;
6355 if ( x_shift
< 0 ) x_shift
= 0;
6356 if ( x_shift
+ (src_width
/ hmul
) > width
)
6357 x_shift
= width
- (src_width
/ hmul
);
6359 y_shift
= lpgm
->gmptGlyphOrigin
.y
- ft_face
->glyph
->bitmap_top
;
6360 if ( y_shift
< 0 ) y_shift
= 0;
6361 if ( y_shift
+ (src_height
/ vmul
) > height
)
6362 y_shift
= height
- (src_height
/ vmul
);
6364 dst
+= x_shift
+ y_shift
* ( pitch
/ 4 );
6365 while ( src_height
)
6367 for ( x
= 0; x
< src_width
/ hmul
; x
++ )
6371 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
6372 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6373 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
6374 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6378 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
6379 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
6380 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
6381 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
6384 src
+= src_pitch
* vmul
;
6393 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
6405 int contour
, point
= 0, first_pt
;
6406 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6407 TTPOLYGONHEADER
*pph
;
6409 DWORD pph_start
, cpfx
, type
;
6411 if(buflen
== 0) buf
= NULL
;
6413 if (needsTransform
&& buf
) {
6414 pFT_Outline_Transform(outline
, &transMat
);
6417 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6418 /* Ignore contours containing one point */
6419 if(point
== outline
->contours
[contour
]) {
6425 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6428 pph
->dwType
= TT_POLYGON_TYPE
;
6429 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6431 needed
+= sizeof(*pph
);
6433 while(point
<= outline
->contours
[contour
]) {
6434 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6435 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6436 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6440 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6443 } while(point
<= outline
->contours
[contour
] &&
6444 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6445 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6446 /* At the end of a contour Windows adds the start point, but
6448 if(point
> outline
->contours
[contour
] &&
6449 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6451 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6453 } else if(point
<= outline
->contours
[contour
] &&
6454 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6455 /* add closing pt for bezier */
6457 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6465 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6468 pph
->cb
= needed
- pph_start
;
6474 /* Convert the quadratic Beziers to cubic Beziers.
6475 The parametric eqn for a cubic Bezier is, from PLRM:
6476 r(t) = at^3 + bt^2 + ct + r0
6477 with the control points:
6482 A quadratic Bezier has the form:
6483 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6485 So equating powers of t leads to:
6486 r1 = 2/3 p1 + 1/3 p0
6487 r2 = 2/3 p1 + 1/3 p2
6488 and of course r0 = p0, r3 = p2
6491 int contour
, point
= 0, first_pt
;
6492 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
6493 TTPOLYGONHEADER
*pph
;
6495 DWORD pph_start
, cpfx
, type
;
6496 FT_Vector cubic_control
[4];
6497 if(buflen
== 0) buf
= NULL
;
6499 if (needsTransform
&& buf
) {
6500 pFT_Outline_Transform(outline
, &transMat
);
6503 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
6505 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
6508 pph
->dwType
= TT_POLYGON_TYPE
;
6509 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6511 needed
+= sizeof(*pph
);
6513 while(point
<= outline
->contours
[contour
]) {
6514 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
6515 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
6516 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6519 if(type
== TT_PRIM_LINE
) {
6521 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6525 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6528 /* FIXME: Possible optimization in endpoint calculation
6529 if there are two consecutive curves */
6530 cubic_control
[0] = outline
->points
[point
-1];
6531 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
6532 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6533 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6534 cubic_control
[0].x
>>= 1;
6535 cubic_control
[0].y
>>= 1;
6537 if(point
+1 > outline
->contours
[contour
])
6538 cubic_control
[3] = outline
->points
[first_pt
];
6540 cubic_control
[3] = outline
->points
[point
+1];
6541 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
6542 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6543 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6544 cubic_control
[3].x
>>= 1;
6545 cubic_control
[3].y
>>= 1;
6548 /* r1 = 1/3 p0 + 2/3 p1
6549 r2 = 1/3 p2 + 2/3 p1 */
6550 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6551 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6552 cubic_control
[2] = cubic_control
[1];
6553 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6554 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6555 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6556 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6558 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6559 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6560 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6565 } while(point
<= outline
->contours
[contour
] &&
6566 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6567 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6568 /* At the end of a contour Windows adds the start point,
6569 but only for Beziers and we've already done that.
6571 if(point
<= outline
->contours
[contour
] &&
6572 outline
->tags
[point
] & FT_Curve_Tag_On
) {
6573 /* This is the closing pt of a bezier, but we've already
6574 added it, so just inc point and carry on */
6581 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6584 pph
->cb
= needed
- pph_start
;
6590 FIXME("Unsupported format %d\n", format
);
6596 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
6598 FT_Face ft_face
= font
->ft_face
;
6599 FT_WinFNT_HeaderRec winfnt_header
;
6600 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
6601 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
6602 font
->potm
->otmSize
= size
;
6604 #define TM font->potm->otmTextMetrics
6605 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
6607 TM
.tmHeight
= winfnt_header
.pixel_height
;
6608 TM
.tmAscent
= winfnt_header
.ascent
;
6609 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
6610 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
6611 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
6612 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
6613 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
6614 TM
.tmWeight
= winfnt_header
.weight
;
6616 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
6617 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
6618 TM
.tmFirstChar
= winfnt_header
.first_char
;
6619 TM
.tmLastChar
= winfnt_header
.last_char
;
6620 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
6621 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
6622 TM
.tmItalic
= winfnt_header
.italic
;
6623 TM
.tmUnderlined
= font
->underline
;
6624 TM
.tmStruckOut
= font
->strikeout
;
6625 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
6626 TM
.tmCharSet
= winfnt_header
.charset
;
6630 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
6631 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
6632 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6633 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
6634 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
6635 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
6636 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
6637 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
6639 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6640 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6642 TM
.tmLastChar
= 255;
6643 TM
.tmDefaultChar
= 32;
6644 TM
.tmBreakChar
= 32;
6645 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
6646 TM
.tmUnderlined
= font
->underline
;
6647 TM
.tmStruckOut
= font
->strikeout
;
6648 /* NB inverted meaning of TMPF_FIXED_PITCH */
6649 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
6650 TM
.tmCharSet
= font
->charset
;
6658 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
6660 double scale_x
, scale_y
;
6664 scale_x
= (double)font
->aveWidth
;
6665 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6668 scale_x
= font
->scale_y
;
6670 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6671 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6673 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6674 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6676 SCALE_Y(ptm
->tmHeight
);
6677 SCALE_Y(ptm
->tmAscent
);
6678 SCALE_Y(ptm
->tmDescent
);
6679 SCALE_Y(ptm
->tmInternalLeading
);
6680 SCALE_Y(ptm
->tmExternalLeading
);
6681 SCALE_Y(ptm
->tmOverhang
);
6683 SCALE_X(ptm
->tmAveCharWidth
);
6684 SCALE_X(ptm
->tmMaxCharWidth
);
6690 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
6692 double scale_x
, scale_y
;
6696 scale_x
= (double)font
->aveWidth
;
6697 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6700 scale_x
= font
->scale_y
;
6702 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
6703 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
6705 scale_font_metrics(font
, &potm
->otmTextMetrics
);
6707 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6708 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6710 SCALE_Y(potm
->otmAscent
);
6711 SCALE_Y(potm
->otmDescent
);
6712 SCALE_Y(potm
->otmLineGap
);
6713 SCALE_Y(potm
->otmsCapEmHeight
);
6714 SCALE_Y(potm
->otmsXHeight
);
6715 SCALE_Y(potm
->otmrcFontBox
.top
);
6716 SCALE_Y(potm
->otmrcFontBox
.bottom
);
6717 SCALE_X(potm
->otmrcFontBox
.left
);
6718 SCALE_X(potm
->otmrcFontBox
.right
);
6719 SCALE_Y(potm
->otmMacAscent
);
6720 SCALE_Y(potm
->otmMacDescent
);
6721 SCALE_Y(potm
->otmMacLineGap
);
6722 SCALE_X(potm
->otmptSubscriptSize
.x
);
6723 SCALE_Y(potm
->otmptSubscriptSize
.y
);
6724 SCALE_X(potm
->otmptSubscriptOffset
.x
);
6725 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
6726 SCALE_X(potm
->otmptSuperscriptSize
.x
);
6727 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
6728 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
6729 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
6730 SCALE_Y(potm
->otmsStrikeoutSize
);
6731 SCALE_Y(potm
->otmsStrikeoutPosition
);
6732 SCALE_Y(potm
->otmsUnderscoreSize
);
6733 SCALE_Y(potm
->otmsUnderscorePosition
);
6739 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
6743 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
6745 /* Make sure that the font has sane width/height ratio */
6748 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
6750 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
6755 *ptm
= font
->potm
->otmTextMetrics
;
6756 scale_font_metrics(font
, ptm
);
6760 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
6764 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
6766 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
6772 static BOOL
get_outline_text_metrics(GdiFont
*font
)
6775 FT_Face ft_face
= font
->ft_face
;
6776 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
6778 TT_HoriHeader
*pHori
;
6779 TT_Postscript
*pPost
;
6781 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
6783 INT ascent
, descent
;
6785 TRACE("font=%p\n", font
);
6787 if(!FT_IS_SCALABLE(ft_face
))
6790 needed
= sizeof(*font
->potm
);
6792 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
6793 family_nameW
= strdupW(font
->name
);
6795 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
6797 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6800 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6801 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
6803 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
6805 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
6807 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6810 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6811 face_nameW
= strdupW(font
->name
);
6813 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
6814 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
6816 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
6818 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
6821 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
6822 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
6823 full_nameW
= strdupW(fake_nameW
);
6825 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
6827 /* These names should be read from the TT name table */
6829 /* length of otmpFamilyName */
6832 /* length of otmpFaceName */
6835 /* length of otmpStyleName */
6838 /* length of otmpFullName */
6842 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
6844 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
6846 FIXME("Can't find OS/2 table - not TT font?\n");
6850 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
6852 FIXME("Can't find HHEA table - not TT font?\n");
6856 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
6858 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",
6859 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
6860 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
6861 pOS2
->xAvgCharWidth
,
6862 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
6863 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
6864 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
6866 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
6867 font
->potm
->otmSize
= needed
;
6869 #define TM font->potm->otmTextMetrics
6871 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
6872 ascent
= pHori
->Ascender
;
6873 descent
= -pHori
->Descender
;
6875 ascent
= pOS2
->usWinAscent
;
6876 descent
= pOS2
->usWinDescent
;
6879 font
->ntmCellHeight
= ascent
+ descent
;
6880 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
6882 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6883 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6886 TM
.tmAscent
= font
->yMax
;
6887 TM
.tmDescent
= -font
->yMin
;
6888 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
6890 TM
.tmAscent
= SCALE_Y(ascent
);
6891 TM
.tmDescent
= SCALE_Y(descent
);
6892 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
6895 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
6898 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6900 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
6901 ((ascent
+ descent
) -
6902 (pHori
->Ascender
- pHori
->Descender
))));
6904 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
6905 if (TM
.tmAveCharWidth
== 0) {
6906 TM
.tmAveCharWidth
= 1;
6908 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
6909 TM
.tmWeight
= FW_REGULAR
;
6910 if (font
->fake_bold
)
6911 TM
.tmWeight
= FW_BOLD
;
6914 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
6916 if (pOS2
->usWeightClass
> FW_MEDIUM
)
6917 TM
.tmWeight
= pOS2
->usWeightClass
;
6919 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
6920 TM
.tmWeight
= pOS2
->usWeightClass
;
6923 TM
.tmDigitizedAspectX
= 96; /* FIXME */
6924 TM
.tmDigitizedAspectY
= 96; /* FIXME */
6925 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6926 * symbol range to 0 - f0ff
6929 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
6934 case 1257: /* Baltic */
6935 TM
.tmLastChar
= 0xf8fd;
6938 TM
.tmLastChar
= 0xf0ff;
6940 TM
.tmBreakChar
= 0x20;
6941 TM
.tmDefaultChar
= 0x1f;
6945 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
6946 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
6948 if(pOS2
->usFirstCharIndex
<= 1)
6949 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
6950 else if (pOS2
->usFirstCharIndex
> 0xff)
6951 TM
.tmBreakChar
= 0x20;
6953 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
6954 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
6956 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
6957 TM
.tmUnderlined
= font
->underline
;
6958 TM
.tmStruckOut
= font
->strikeout
;
6960 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6961 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
6962 (pOS2
->version
== 0xFFFFU
||
6963 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
6964 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
6966 TM
.tmPitchAndFamily
= 0;
6968 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
6970 case PAN_FAMILY_SCRIPT
:
6971 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
6974 case PAN_FAMILY_DECORATIVE
:
6975 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
6980 case PAN_FAMILY_TEXT_DISPLAY
:
6981 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
6982 /* which is clearly not what the panose spec says. */
6984 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
6985 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
6986 TM
.tmPitchAndFamily
= FF_MODERN
;
6989 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
6994 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
6997 case PAN_SERIF_COVE
:
6998 case PAN_SERIF_OBTUSE_COVE
:
6999 case PAN_SERIF_SQUARE_COVE
:
7000 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7001 case PAN_SERIF_SQUARE
:
7002 case PAN_SERIF_THIN
:
7003 case PAN_SERIF_BONE
:
7004 case PAN_SERIF_EXAGGERATED
:
7005 case PAN_SERIF_TRIANGLE
:
7006 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7009 case PAN_SERIF_NORMAL_SANS
:
7010 case PAN_SERIF_OBTUSE_SANS
:
7011 case PAN_SERIF_PERP_SANS
:
7012 case PAN_SERIF_FLARED
:
7013 case PAN_SERIF_ROUNDED
:
7014 TM
.tmPitchAndFamily
|= FF_SWISS
;
7021 if(FT_IS_SCALABLE(ft_face
))
7022 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7024 if(FT_IS_SFNT(ft_face
))
7026 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7027 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7029 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7032 TM
.tmCharSet
= font
->charset
;
7034 font
->potm
->otmFiller
= 0;
7035 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7036 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7037 font
->potm
->otmfsType
= pOS2
->fsType
;
7038 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7039 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7040 font
->potm
->otmItalicAngle
= 0; /* POST table */
7041 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7042 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7043 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7044 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7045 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7046 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7047 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7048 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7049 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7050 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7051 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7052 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7053 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7054 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7055 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7056 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7057 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7058 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7059 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7060 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7061 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7062 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7063 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7064 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7066 font
->potm
->otmsUnderscoreSize
= 0;
7067 font
->potm
->otmsUnderscorePosition
= 0;
7069 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7070 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7076 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7077 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7078 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7079 strcpyW((WCHAR
*)cp
, family_nameW
);
7081 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7082 strcpyW((WCHAR
*)cp
, style_nameW
);
7084 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7085 strcpyW((WCHAR
*)cp
, face_nameW
);
7087 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7088 strcpyW((WCHAR
*)cp
, full_nameW
);
7092 HeapFree(GetProcessHeap(), 0, style_nameW
);
7093 HeapFree(GetProcessHeap(), 0, family_nameW
);
7094 HeapFree(GetProcessHeap(), 0, face_nameW
);
7095 HeapFree(GetProcessHeap(), 0, full_nameW
);
7099 /*************************************************************
7100 * freetype_GetGlyphOutline
7102 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7103 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7105 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7111 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7112 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7116 EnterCriticalSection( &freetype_cs
);
7117 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7118 LeaveCriticalSection( &freetype_cs
);
7122 /*************************************************************
7123 * freetype_GetTextMetrics
7125 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7127 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7132 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7133 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7137 EnterCriticalSection( &freetype_cs
);
7138 ret
= get_text_metrics( physdev
->font
, metrics
);
7139 LeaveCriticalSection( &freetype_cs
);
7143 /*************************************************************
7144 * freetype_GetOutlineTextMetrics
7146 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7148 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7153 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7154 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7157 TRACE("font=%p\n", physdev
->font
);
7159 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7162 EnterCriticalSection( &freetype_cs
);
7164 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7166 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7168 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7169 scale_outline_font_metrics(physdev
->font
, potm
);
7171 ret
= physdev
->font
->potm
->otmSize
;
7173 LeaveCriticalSection( &freetype_cs
);
7177 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7179 child
->font
= alloc_font();
7180 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7181 if(!child
->font
->ft_face
)
7183 free_font(child
->font
);
7188 child
->font
->font_desc
= font
->font_desc
;
7189 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7190 child
->font
->orientation
= font
->orientation
;
7191 child
->font
->scale_y
= font
->scale_y
;
7192 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7193 child
->font
->base_font
= font
;
7194 TRACE("created child font %p for base %p\n", child
->font
, font
);
7198 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
7201 CHILD_FONT
*child_font
;
7204 font
= font
->base_font
;
7206 *linked_font
= font
;
7208 if((*glyph
= get_glyph_index(font
, c
)))
7210 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7214 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7216 if(!child_font
->font
)
7217 if(!load_child_font(font
, child_font
))
7220 if(!child_font
->font
->ft_face
)
7222 g
= get_glyph_index(child_font
->font
, c
);
7223 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7227 *linked_font
= child_font
->font
;
7234 /*************************************************************
7235 * freetype_GetCharWidth
7237 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7239 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7243 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7247 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7248 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7251 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7254 EnterCriticalSection( &freetype_cs
);
7255 for(c
= firstChar
; c
<= lastChar
; c
++) {
7256 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7257 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7259 LeaveCriticalSection( &freetype_cs
);
7263 /*************************************************************
7264 * freetype_GetCharABCWidths
7266 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7268 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7271 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7275 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7276 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7279 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7282 EnterCriticalSection( &freetype_cs
);
7284 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7285 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7287 LeaveCriticalSection( &freetype_cs
);
7291 /*************************************************************
7292 * freetype_GetCharABCWidthsI
7294 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7296 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7299 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7303 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7304 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7307 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7311 EnterCriticalSection( &freetype_cs
);
7313 for(c
= 0; c
< count
; c
++, buffer
++)
7314 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7315 &gm
, buffer
, 0, NULL
, &identity
);
7317 LeaveCriticalSection( &freetype_cs
);
7321 /*************************************************************
7322 * freetype_GetTextExtentExPoint
7324 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7326 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7330 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7334 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7335 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7338 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7341 EnterCriticalSection( &freetype_cs
);
7343 for (idx
= pos
= 0; idx
< count
; idx
++)
7345 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7346 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7350 LeaveCriticalSection( &freetype_cs
);
7354 /*************************************************************
7355 * freetype_GetTextExtentExPointI
7357 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7359 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7363 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7367 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7368 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7371 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7374 EnterCriticalSection( &freetype_cs
);
7376 for (idx
= pos
= 0; idx
< count
; idx
++)
7378 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7379 &gm
, &abc
, 0, NULL
, &identity
);
7380 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7384 LeaveCriticalSection( &freetype_cs
);
7388 /*************************************************************
7389 * freetype_GetFontData
7391 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7393 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7397 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7398 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7401 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7402 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7403 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7405 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7408 /*************************************************************
7409 * freetype_GetTextFace
7411 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7414 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7418 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7419 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7422 n
= strlenW(physdev
->font
->name
) + 1;
7425 lstrcpynW(str
, physdev
->font
->name
, count
);
7431 /*************************************************************
7432 * freetype_GetTextCharsetInfo
7434 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7436 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7440 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7441 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7443 if (fs
) *fs
= physdev
->font
->fs
;
7444 return physdev
->font
->charset
;
7447 /* Retrieve a list of supported Unicode ranges for a given font.
7448 * Can be called with NULL gs to calculate the buffer size. Returns
7449 * the number of ranges found.
7451 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7453 DWORD num_ranges
= 0;
7455 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7458 FT_ULong char_code
, char_code_prev
;
7461 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7463 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7464 face
->num_glyphs
, glyph_code
, char_code
);
7466 if (!glyph_code
) return 0;
7470 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7471 gs
->ranges
[0].cGlyphs
= 0;
7472 gs
->cGlyphsSupported
= 0;
7478 if (char_code
< char_code_prev
)
7480 ERR("expected increasing char code from FT_Get_Next_Char\n");
7483 if (char_code
- char_code_prev
> 1)
7488 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
7489 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
7490 gs
->cGlyphsSupported
++;
7495 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
7496 gs
->cGlyphsSupported
++;
7498 char_code_prev
= char_code
;
7499 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
7503 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
7508 /*************************************************************
7509 * freetype_GetFontUnicodeRanges
7511 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
7513 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7514 DWORD size
, num_ranges
;
7518 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
7519 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
7522 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
7523 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
7526 glyphset
->cbThis
= size
;
7527 glyphset
->cRanges
= num_ranges
;
7528 glyphset
->flAccel
= 0;
7533 /*************************************************************
7534 * freetype_FontIsLinked
7536 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
7538 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7543 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
7544 return dev
->funcs
->pFontIsLinked( dev
);
7548 EnterCriticalSection( &freetype_cs
);
7549 ret
= !list_empty(&physdev
->font
->child_fonts
);
7550 LeaveCriticalSection( &freetype_cs
);
7554 /*************************************************************************
7555 * GetRasterizerCaps (GDI32.@)
7557 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
7559 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
7560 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
7561 lprs
->nLanguageID
= 0;
7565 /*************************************************************
7566 * freetype_GdiRealizationInfo
7568 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
7570 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7571 realization_info_t
*info
= ptr
;
7575 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
7576 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
7579 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
7582 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
7585 info
->cache_num
= physdev
->font
->cache_num
;
7586 info
->unknown2
= -1;
7590 /*************************************************************************
7591 * Kerning support for TrueType fonts
7593 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7595 struct TT_kern_table
7601 struct TT_kern_subtable
7610 USHORT horizontal
: 1;
7612 USHORT cross_stream
: 1;
7613 USHORT override
: 1;
7614 USHORT reserved1
: 4;
7620 struct TT_format0_kern_subtable
7624 USHORT entrySelector
;
7635 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
7636 const struct TT_format0_kern_subtable
*tt_f0_ks
,
7637 const USHORT
*glyph_to_char
,
7638 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
7641 const struct TT_kern_pair
*tt_kern_pair
;
7643 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
7645 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
7647 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7648 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
7649 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
7651 if (!kern_pair
|| !cPairs
)
7654 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
7656 nPairs
= min(nPairs
, cPairs
);
7658 for (i
= 0; i
< nPairs
; i
++)
7660 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
7661 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
7662 /* this algorithm appears to better match what Windows does */
7663 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
7664 if (kern_pair
->iKernAmount
< 0)
7666 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
7667 kern_pair
->iKernAmount
-= font
->ppem
;
7669 else if (kern_pair
->iKernAmount
> 0)
7671 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
7672 kern_pair
->iKernAmount
+= font
->ppem
;
7674 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
7676 TRACE("left %u right %u value %d\n",
7677 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
7681 TRACE("copied %u entries\n", nPairs
);
7685 /*************************************************************
7686 * freetype_GetKerningPairs
7688 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
7692 const struct TT_kern_table
*tt_kern_table
;
7693 const struct TT_kern_subtable
*tt_kern_subtable
;
7695 USHORT
*glyph_to_char
;
7697 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7699 if (!(font
= physdev
->font
))
7701 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
7702 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
7706 EnterCriticalSection( &freetype_cs
);
7707 if (font
->total_kern_pairs
!= (DWORD
)-1)
7709 if (cPairs
&& kern_pair
)
7711 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7712 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7714 else cPairs
= font
->total_kern_pairs
;
7716 LeaveCriticalSection( &freetype_cs
);
7720 font
->total_kern_pairs
= 0;
7722 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
7724 if (length
== GDI_ERROR
)
7726 TRACE("no kerning data in the font\n");
7727 LeaveCriticalSection( &freetype_cs
);
7731 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
7734 WARN("Out of memory\n");
7735 LeaveCriticalSection( &freetype_cs
);
7739 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
7741 /* build a glyph index to char code map */
7742 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
7745 WARN("Out of memory allocating a glyph index to char code map\n");
7746 HeapFree(GetProcessHeap(), 0, buf
);
7747 LeaveCriticalSection( &freetype_cs
);
7751 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7757 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
7759 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7760 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
7764 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7766 /* FIXME: This doesn't match what Windows does: it does some fancy
7767 * things with duplicate glyph index to char code mappings, while
7768 * we just avoid overriding existing entries.
7770 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
7771 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
7773 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
7780 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
7781 for (n
= 0; n
<= 65535; n
++)
7782 glyph_to_char
[n
] = (USHORT
)n
;
7785 tt_kern_table
= buf
;
7786 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
7787 TRACE("version %u, nTables %u\n",
7788 GET_BE_WORD(tt_kern_table
->version
), nTables
);
7790 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
7792 for (i
= 0; i
< nTables
; i
++)
7794 struct TT_kern_subtable tt_kern_subtable_copy
;
7796 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
7797 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
7798 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
7800 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7801 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
7802 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
7804 /* According to the TrueType specification this is the only format
7805 * that will be properly interpreted by Windows and OS/2
7807 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
7809 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
7811 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7812 glyph_to_char
, NULL
, 0);
7813 font
->total_kern_pairs
+= new_chunk
;
7815 if (!font
->kern_pairs
)
7816 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
7817 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7819 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
7820 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
7822 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
7823 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
7826 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
7828 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
7831 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
7832 HeapFree(GetProcessHeap(), 0, buf
);
7834 if (cPairs
&& kern_pair
)
7836 cPairs
= min(cPairs
, font
->total_kern_pairs
);
7837 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
7839 else cPairs
= font
->total_kern_pairs
;
7841 LeaveCriticalSection( &freetype_cs
);
7845 static const struct gdi_dc_funcs freetype_funcs
=
7847 NULL
, /* pAbortDoc */
7848 NULL
, /* pAbortPath */
7849 NULL
, /* pAlphaBlend */
7850 NULL
, /* pAngleArc */
7853 NULL
, /* pBeginPath */
7854 NULL
, /* pBlendImage */
7856 NULL
, /* pCloseFigure */
7857 NULL
, /* pCreateCompatibleDC */
7858 freetype_CreateDC
, /* pCreateDC */
7859 freetype_DeleteDC
, /* pDeleteDC */
7860 NULL
, /* pDeleteObject */
7861 NULL
, /* pDeviceCapabilities */
7862 NULL
, /* pEllipse */
7864 NULL
, /* pEndPage */
7865 NULL
, /* pEndPath */
7866 freetype_EnumFonts
, /* pEnumFonts */
7867 NULL
, /* pEnumICMProfiles */
7868 NULL
, /* pExcludeClipRect */
7869 NULL
, /* pExtDeviceMode */
7870 NULL
, /* pExtEscape */
7871 NULL
, /* pExtFloodFill */
7872 NULL
, /* pExtSelectClipRgn */
7873 NULL
, /* pExtTextOut */
7874 NULL
, /* pFillPath */
7875 NULL
, /* pFillRgn */
7876 NULL
, /* pFlattenPath */
7877 freetype_FontIsLinked
, /* pFontIsLinked */
7878 NULL
, /* pFrameRgn */
7879 NULL
, /* pGdiComment */
7880 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
7881 NULL
, /* pGetBoundsRect */
7882 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
7883 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
7884 freetype_GetCharWidth
, /* pGetCharWidth */
7885 NULL
, /* pGetDeviceCaps */
7886 NULL
, /* pGetDeviceGammaRamp */
7887 freetype_GetFontData
, /* pGetFontData */
7888 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
7889 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
7890 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
7891 NULL
, /* pGetICMProfile */
7892 NULL
, /* pGetImage */
7893 freetype_GetKerningPairs
, /* pGetKerningPairs */
7894 NULL
, /* pGetNearestColor */
7895 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
7896 NULL
, /* pGetPixel */
7897 NULL
, /* pGetSystemPaletteEntries */
7898 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
7899 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
7900 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
7901 freetype_GetTextFace
, /* pGetTextFace */
7902 freetype_GetTextMetrics
, /* pGetTextMetrics */
7903 NULL
, /* pGradientFill */
7904 NULL
, /* pIntersectClipRect */
7905 NULL
, /* pInvertRgn */
7907 NULL
, /* pModifyWorldTransform */
7909 NULL
, /* pOffsetClipRgn */
7910 NULL
, /* pOffsetViewportOrg */
7911 NULL
, /* pOffsetWindowOrg */
7912 NULL
, /* pPaintRgn */
7915 NULL
, /* pPolyBezier */
7916 NULL
, /* pPolyBezierTo */
7917 NULL
, /* pPolyDraw */
7918 NULL
, /* pPolyPolygon */
7919 NULL
, /* pPolyPolyline */
7920 NULL
, /* pPolygon */
7921 NULL
, /* pPolyline */
7922 NULL
, /* pPolylineTo */
7923 NULL
, /* pPutImage */
7924 NULL
, /* pRealizeDefaultPalette */
7925 NULL
, /* pRealizePalette */
7926 NULL
, /* pRectangle */
7927 NULL
, /* pResetDC */
7928 NULL
, /* pRestoreDC */
7929 NULL
, /* pRoundRect */
7931 NULL
, /* pScaleViewportExt */
7932 NULL
, /* pScaleWindowExt */
7933 NULL
, /* pSelectBitmap */
7934 NULL
, /* pSelectBrush */
7935 NULL
, /* pSelectClipPath */
7936 freetype_SelectFont
, /* pSelectFont */
7937 NULL
, /* pSelectPalette */
7938 NULL
, /* pSelectPen */
7939 NULL
, /* pSetArcDirection */
7940 NULL
, /* pSetBkColor */
7941 NULL
, /* pSetBkMode */
7942 NULL
, /* pSetDCBrushColor */
7943 NULL
, /* pSetDCPenColor */
7944 NULL
, /* pSetDIBColorTable */
7945 NULL
, /* pSetDIBitsToDevice */
7946 NULL
, /* pSetDeviceClipping */
7947 NULL
, /* pSetDeviceGammaRamp */
7948 NULL
, /* pSetLayout */
7949 NULL
, /* pSetMapMode */
7950 NULL
, /* pSetMapperFlags */
7951 NULL
, /* pSetPixel */
7952 NULL
, /* pSetPolyFillMode */
7953 NULL
, /* pSetROP2 */
7954 NULL
, /* pSetRelAbs */
7955 NULL
, /* pSetStretchBltMode */
7956 NULL
, /* pSetTextAlign */
7957 NULL
, /* pSetTextCharacterExtra */
7958 NULL
, /* pSetTextColor */
7959 NULL
, /* pSetTextJustification */
7960 NULL
, /* pSetViewportExt */
7961 NULL
, /* pSetViewportOrg */
7962 NULL
, /* pSetWindowExt */
7963 NULL
, /* pSetWindowOrg */
7964 NULL
, /* pSetWorldTransform */
7965 NULL
, /* pStartDoc */
7966 NULL
, /* pStartPage */
7967 NULL
, /* pStretchBlt */
7968 NULL
, /* pStretchDIBits */
7969 NULL
, /* pStrokeAndFillPath */
7970 NULL
, /* pStrokePath */
7971 NULL
, /* pUnrealizePalette */
7972 NULL
, /* pWidenPath */
7973 NULL
, /* wine_get_wgl_driver */
7974 GDI_PRIORITY_FONT_DRV
/* priority */
7977 #else /* HAVE_FREETYPE */
7979 /*************************************************************************/
7981 BOOL
WineEngInit(void)
7986 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7988 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7992 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
7994 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
7998 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8000 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8004 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8005 LPCWSTR font_file
, LPCWSTR font_path
)
8011 /*************************************************************************
8012 * GetRasterizerCaps (GDI32.@)
8014 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8016 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8018 lprs
->nLanguageID
= 0;
8022 #endif /* HAVE_FREETYPE */